diff --git a/.github/workflows/build_unittest_container.yml b/.github/workflows/build_unittest_container.yml deleted file mode 100644 index 56506e05..00000000 --- a/.github/workflows/build_unittest_container.yml +++ /dev/null @@ -1,45 +0,0 @@ -# CI step to build the unittest container to be used for the other CI steps -# publish the container in the github container registry - -name: Checks - -# This workflow should only run when the Dockerfile changes -on: - push: - paths: - - docker/Dockerfile - pull_request: - paths: - - docker/Dockerfile -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }}-crown-unittest - -jobs: - build_unittest_container: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - name: Build and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - file: docker/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 49da5978..9a377242 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,8 +1,6 @@ name: Checks on: - workflow_run: - workflows: ["build_unittest_container"] push: branches: - main @@ -12,6 +10,7 @@ on: # Settings go here! env: + ENV_NAME: env BUILD_TYPE: Release ANALYSIS: unittest CONFIG: unittest_config @@ -25,188 +24,172 @@ env: TWO_FRIENDS_CONFIG: unittest_friends_2 FRIEND_SHIFTS: "nominal,jesUncTotalUp,jesUncTotalDown,tauMuFakeEsDown" +# This ensures every step runs in a login shell, automatically activating conda +defaults: + run: + shell: bash -el {0} + jobs: build_project: runs-on: ubuntu-24.04 container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 + image: kingmakerimages/kingmaker_standalone:V1 options: --user 0 # run as root steps: - name: Clone project - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CERN_GITLAB_PRIVATE_KEY }} submodules: "recursive" ssh-strict: "false" ssh-known-hosts: "[gitlab.cern.ch]:7999 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubVS0czgKaPkC5cfB75CI3XjgWBv7pj2ILiZezVf8okkCAYr+bf4w6VrH2pyv3NRUW5Mm8U/3zoSNcrYIqhFFpz6R62/3xt8hMrPKJKstbt1lSIr8QhEyD24SJEKugMi560BWRPkTzXrrFgxz0X4vuKKytpvihRsccZ7F1JaX76UCWEJ3Xr2BFCEnnN6gj9nvFr4gvSMneunWVLGw2KcHwS1OJfnWBlp3fB0rYWSxZAoVjcjZjvv3hioEftaTapff2PkdQIX//N9Cc555FzdmMzixTvU5j/i+QvjxWVbEBNSKI6te6udC4fYUZMePs2QQnqw9mXUQtaQtw+HV7utuw==" - - name: Mark git directory as safe - run: git config --global --add safe.directory ${{github.workspace}} + - name: Mark all git directories as safe + run: git config --global --add safe.directory '*' - name: Create Build Environment - shell: bash - run: cmake -E make_directory ${{github.workspace}}/build + run: cmake -E make_directory build - name: adding a system path run: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Configure CMake - shell: bash - run: cd ${{github.workspace}}/build && cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DANALYSIS=$ANALYSIS -DCONFIG=$CONFIG -DSAMPLES=$SAMPLES -DERAS=$ERAS -DSCOPES=$SCOPES -DSHIFTS=$SHIFTS -DOPTIMIZED=false -DONNXRUNTIME_INCLUDE_DIR=/opt/onnxruntime + run: | + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DANALYSIS=$ANALYSIS \ + -DCONFIG=$CONFIG \ + -DSAMPLES=$SAMPLES \ + -DERAS=$ERAS \ + -DSCOPES=$SCOPES \ + -DSHIFTS=$SHIFTS \ + -DOPTIMIZED=false - name: Build - shell: bash - run: cd ${{github.workspace}}/build && make install -j 2 + run: make -C build install -j$(nproc) - name: Test - shell: bash - run: cd ${{github.workspace}}/build && ctest -V --label-regex "ntuple.*." + run: ctest --test-dir build -V --label-regex "ntuple.*." build_single_friend: runs-on: ubuntu-24.04 container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 + image: kingmakerimages/kingmaker_standalone:V1 options: --user 0 # run as root steps: - - name: Clone project - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CERN_GITLAB_PRIVATE_KEY }} submodules: "recursive" ssh-strict: "false" ssh-known-hosts: "[gitlab.cern.ch]:7999 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubVS0czgKaPkC5cfB75CI3XjgWBv7pj2ILiZezVf8okkCAYr+bf4w6VrH2pyv3NRUW5Mm8U/3zoSNcrYIqhFFpz6R62/3xt8hMrPKJKstbt1lSIr8QhEyD24SJEKugMi560BWRPkTzXrrFgxz0X4vuKKytpvihRsccZ7F1JaX76UCWEJ3Xr2BFCEnnN6gj9nvFr4gvSMneunWVLGw2KcHwS1OJfnWBlp3fB0rYWSxZAoVjcjZjvv3hioEftaTapff2PkdQIX//N9Cc555FzdmMzixTvU5j/i+QvjxWVbEBNSKI6te6udC4fYUZMePs2QQnqw9mXUQtaQtw+HV7utuw==" - - name: Mark git directory as safe - run: git config --global --add safe.directory ${{github.workspace}} + - name: Mark all git directories as safe + run: git config --global --add safe.directory '*' - name: Create Build Environment - shell: bash - run: cmake -E make_directory ${{github.workspace}}/build + run: cmake -E make_directory build - name: adding a system path run: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Configure CMake - shell: bash - run: cd ${{github.workspace}}/build && cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DANALYSIS=$ANALYSIS -DCONFIG=$SINGLE_FRIEND_CONFIG -DSAMPLES=$SAMPLES -DERAS=$ERAS -DSCOPES=$SINGLE_FRIEND_SCOPES -DSHIFTS=$FRIEND_SHIFTS -DOPTIMIZED=false -DQUANTITIESMAP="dummy" -DONNXRUNTIME_INCLUDE_DIR=/opt/onnxruntime + run: | + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DANALYSIS=$ANALYSIS \ + -DCONFIG=$SINGLE_FRIEND_CONFIG \ + -DSAMPLES=$SAMPLES \ + -DERAS=$ERAS \ + -DSCOPES=$SINGLE_FRIEND_SCOPES \ + -DSHIFTS=$FRIEND_SHIFTS \ + -DOPTIMIZED=false \ + -DQUANTITIESMAP="dummy" - name: Build - shell: bash - run: cd ${{github.workspace}}/build && make install -j 2 + run: make -C build install -j$(nproc) - name: Test - shell: bash - run: cd ${{github.workspace}}/build && ctest -V --label-regex "single_friend.*." + run: ctest --test-dir build -V --label-regex "single_friend.*." build_two_friends: runs-on: ubuntu-24.04 container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 + image: kingmakerimages/kingmaker_standalone:V1 options: --user 0 # run as root steps: - name: Clone project - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CERN_GITLAB_PRIVATE_KEY }} submodules: "recursive" ssh-strict: "false" ssh-known-hosts: "[gitlab.cern.ch]:7999 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubVS0czgKaPkC5cfB75CI3XjgWBv7pj2ILiZezVf8okkCAYr+bf4w6VrH2pyv3NRUW5Mm8U/3zoSNcrYIqhFFpz6R62/3xt8hMrPKJKstbt1lSIr8QhEyD24SJEKugMi560BWRPkTzXrrFgxz0X4vuKKytpvihRsccZ7F1JaX76UCWEJ3Xr2BFCEnnN6gj9nvFr4gvSMneunWVLGw2KcHwS1OJfnWBlp3fB0rYWSxZAoVjcjZjvv3hioEftaTapff2PkdQIX//N9Cc555FzdmMzixTvU5j/i+QvjxWVbEBNSKI6te6udC4fYUZMePs2QQnqw9mXUQtaQtw+HV7utuw==" - - name: Mark git directory as safe - run: git config --global --add safe.directory ${{github.workspace}} - - - name: Create Build Environment - shell: bash - run: cmake -E make_directory ${{github.workspace}}/build - - - name: adding a system path - run: echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Mark all directories as safe + run: git config --global --add safe.directory '*' - name: Configure CMake - shell: bash - run: cd ${{github.workspace}}/build && cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DANALYSIS=$ANALYSIS -DCONFIG=$TWO_FRIENDS_CONFIG -DSAMPLES=$SAMPLES -DERAS=$ERAS -DSCOPES=$TWO_FRIENDS_SCOPES -DSHIFTS=$FRIEND_SHIFTS -DOPTIMIZED=false -DQUANTITIESMAP="dummy" -DONNXRUNTIME_INCLUDE_DIR=/opt/onnxruntime + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DANALYSIS=$ANALYSIS \ + -DCONFIG=$TWO_FRIENDS_CONFIG \ + -DSAMPLES=$SAMPLES \ + -DERAS=$ERAS \ + -DSCOPES=$TWO_FRIENDS_SCOPES \ + -DSHIFTS=$FRIEND_SHIFTS \ + -DOPTIMIZED=false \ + -DQUANTITIESMAP="dummy" - name: Build - shell: bash - run: cd ${{github.workspace}}/build && make install -j 2 + run: make -C build install -j$(nproc) - name: Test - shell: bash - run: cd ${{github.workspace}}/build && ctest -V --label-regex "two_friends.*." - + run: ctest --test-dir build -V --label-regex "two_friends.*." - python_format: + code_formatting: runs-on: ubuntu-24.04 container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 - options: --user 0 # run as root - + image: kingmakerimages/kingmaker_standalone:V1 + options: --user 0 steps: - - name: apt update - run: apt-get -y update - - - name: Install missing software - run: apt-get install -y git python3-pip && pip install black==23.3.0 --break-system-packages - - - uses: actions/checkout@v2 - - - name: Check Python formatting - shell: bash - run: cd $GITHUB_WORKSPACE && bash checks/python-formatting.sh - - cpp_format: - runs-on: ubuntu-24.04 - container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 - options: --user 0 # run as root - - steps: - - name: apt update - run: apt-get -y update - - - name: Install missing software - run: apt-get install -y git python3-pip && pip install clang-format --break-system-packages - - - uses: actions/checkout@v2 - - - name: Check C++ formatting - shell: bash - run: cd $GITHUB_WORKSPACE && bash checks/cpp-formatting.sh + - name: Clone project + uses: actions/checkout@v4 + - name: Run all formatting checks + run: | + git config --global --add safe.directory '*' + bash ./checks/run-all-checks.sh docs: runs-on: ubuntu-24.04 container: - image: ghcr.io/kit-cms/crown-crown-unittest:pr-334 - options: --user 0 # run as root - + image: kingmakerimages/kingmaker_standalone:V1 + options: --user 0 steps: - - name: apt update - run: apt-get -y update - - - name: Install missing software - run: apt-get install -y git cmake make doxygen python3-pip - - - name: install docs related packages - run: pip install breathe==4.36 sphinx==8.1.3 sphinx_rtd_theme==3.0.2 --break-system-packages - - - uses: actions/checkout@v2 + - name: Clone project + uses: actions/checkout@v4 - name: Create Build Environment - shell: bash run: cmake -E make_directory ${{github.workspace}}/build - name: Configure CMake - shell: bash - run: cd ${{github.workspace}}/build && cmake $GITHUB_WORKSPACE/docs + run: | + cd ${{github.workspace}}/build + cmake $GITHUB_WORKSPACE/docs - name: Build docs - shell: bash - run: cd ${{github.workspace}}/build && make + run: | + cd ${{github.workspace}}/build + make - name: Publish - shell: bash - run: echo "TODO" + run: echo "TODO" \ No newline at end of file diff --git a/.gitignore b/.gitignore index f0a97d00..29fb5e72 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build*/ log/ logs/ generation_logs/ +.cache/* # ignore all analysis in the config folder apart from the unittest and the template analysis_configurations/* !analysis_configurations/quantities diff --git a/CMakeLists.txt b/CMakeLists.txt index 80224639..b27d4e56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,15 +29,6 @@ message( ) message(STATUS "") -message(STATUS "Finding Packages") -# add the different dependencies -include(AddBaseDependencies) -include(AddRoot) -include(AddLogging) -include(AddCorrectionlib) -include(AddOnnxruntime) -include(ConfigurePython) - # installdir if(NOT DEFINED INSTALLDIR) message( @@ -48,15 +39,26 @@ if(NOT DEFINED INSTALLDIR) endif() set(GENERATE_CPP_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +message(STATUS "Finding Packages") +# add the different dependencies +include(AddBaseDependencies) +include(AddRoot) +include(AddDicts) +include(AddLogging) +include(AddCorrectionlib) +include(AddOnnxruntime) +include(ConfigurePython) + # crownlib setup include(ConfigureCrownlib) -if (BUILD_CROWNLIB_ONLY) +if(BUILD_CROWNLIB_ONLY) # exit if only crownlib is being built return() endif() # run the code generation include(CodeGeneration) +message(STATUS "Next is Build") # run the build include(Build) diff --git a/analysis_configurations/unittest/producers/embedding.py b/analysis_configurations/unittest/producers/embedding.py index 41914b0c..9ff717c5 100644 --- a/analysis_configurations/unittest/producers/embedding.py +++ b/analysis_configurations/unittest/producers/embedding.py @@ -2,7 +2,6 @@ from ..quantities import output as q from ..quantities import nanoAOD as nanoAOD - EmbeddingGenWeight = Producer( name="EmbeddingGenWeight", call="event::quantity::Rename({df}, {output}, {input})", diff --git a/analysis_configurations/unittest/producers/muon_sf_friends.py b/analysis_configurations/unittest/producers/muon_sf_friends.py index 459ff2fe..2c5dd7f0 100644 --- a/analysis_configurations/unittest/producers/muon_sf_friends.py +++ b/analysis_configurations/unittest/producers/muon_sf_friends.py @@ -1,7 +1,6 @@ from ..quantities import output as q from code_generation.producer import Producer - MuonIDSF_friends_1 = Producer( name="MuonIDSF_friends_1", call="""embedding::muon::Scalefactor( diff --git a/analysis_configurations/unittest/producers/scalefactors.py b/analysis_configurations/unittest/producers/scalefactors.py index ce730676..57eae370 100644 --- a/analysis_configurations/unittest/producers/scalefactors.py +++ b/analysis_configurations/unittest/producers/scalefactors.py @@ -2,7 +2,6 @@ from code_generation.producer import Producer, ProducerGroup from code_generation.producer import ExtendedVectorProducer - ############################ # Muon ID, ISO SF # The readout is done via correctionlib @@ -157,11 +156,11 @@ correctionManager, {output}, {input}, - "{tau_sf_file}", + "{tau_sf_file}", "{tau_id_discriminator}", "{vsele_tau_id_WP}", "{era}", - "{tau_sf_vsele_barrel}", + "{tau_sf_vsele_barrel}", "{tau_sf_vsele_endcap}") """, input=[q.eta_1, q.tau_decaymode_1, q.gen_match_1], @@ -246,11 +245,11 @@ correctionManager, {output}, {input}, - "{tau_sf_file}", + "{tau_sf_file}", "{tau_id_discriminator}", "{vsele_tau_id_WP}", "{era}", - "{tau_sf_vsele_barrel}", + "{tau_sf_vsele_barrel}", "{tau_sf_vsele_endcap}") """, input=[q.eta_2, q.tau_decaymode_2, q.gen_match_2], diff --git a/analysis_configurations/unittest/producers/taus.py b/analysis_configurations/unittest/producers/taus.py index 822b9512..fa80fc9f 100644 --- a/analysis_configurations/unittest/producers/taus.py +++ b/analysis_configurations/unittest/producers/taus.py @@ -2,7 +2,6 @@ from ..quantities import nanoAOD as nanoAOD from code_generation.producer import Producer, ProducerGroup - ############# # Tau ID cuts ############# diff --git a/checks/cmake-formatting.sh b/checks/cmake-formatting.sh new file mode 100755 index 00000000..3961ff14 --- /dev/null +++ b/checks/cmake-formatting.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +APPLY_FIXES=false +while [[ "$#" -gt 0 ]]; do + case $1 in + --apply) APPLY_FIXES=true ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac + shift +done + +echo "๐Ÿ” Finding CMake files ..." + +# Find tracked CMake files: +# 1. Any file named CMakeLists.txt +# 2. Any file ending in .cmake or .cmake.in +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FILES=$(git ls-files | grep -E '(CMakeLists\.txt|\.cmake(\.in)?)$' | grep -vEf "$SCRIPT_DIR/format_ignore.txt") + +if [[ -z "$FILES" ]]; then + echo "No CMake files found." + exit 0 +fi + +if [ "$APPLY_FIXES" = true ]; then + echo "๐Ÿ›  Running cmake-format to fix formatting..." + # -i: in-place + echo "$FILES" | xargs cmake-format -i + echo "โœ… CMake formatting complete." +else + echo "๐Ÿงช Checking CMake formatting (Dry Run)..." + + # --check: return exit code 1 if files need formatting + if echo "$FILES" | xargs cmake-format --check; then + echo "โœจ CMake files are perfectly formatted!" + exit 0 + else + echo "------------------------------------------------------" + echo "โŒ ERROR: CMake formatting violations found." + echo "Run this script with --apply to fix them." + echo "------------------------------------------------------" + exit 1 + fi +fi \ No newline at end of file diff --git a/checks/cpp-formatting.sh b/checks/cpp-formatting.sh index 89658631..38cc64ac 100644 --- a/checks/cpp-formatting.sh +++ b/checks/cpp-formatting.sh @@ -1,18 +1,44 @@ #!/bin/bash -for FILENAME in $(find . -name "*.[h,c]xx"); -do - clang-format -i "$FILENAME" +APPLY_FIXES=false +while [[ "$#" -gt 0 ]]; do + case $1 in + --apply) APPLY_FIXES=true ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac + shift done -DIFF=$(git --no-pager diff) -if [[ -z $DIFF ]]; -then - echo "Nothing to format, all good!" +echo "๐Ÿ” Finding Python files ..." + +# Find files tracked by git, excluding submodules and ignored files +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FILES=$(git ls-files | grep -E '\.(h(xx)?|c(xx?))$' | grep -vEf "$SCRIPT_DIR/format_ignore.txt") + +if [[ -z "$FILES" ]]; then + echo "No matching files found." exit 0 -else - echo "Found following diff with clang-format:" - git --no-pager diff - echo "Please format the code with clang-format -i /path/to/files using the .clang-format config from this repository" - exit 1 fi + +if [ "$APPLY_FIXES" = true ]; then + echo "๐Ÿ›  Applying clang-format fixes in-place..." + echo "$FILES" | xargs clang-format -i + echo "โœ… Formatting complete." +else + echo "๐Ÿงช Checking C++ formatting (Dry Run)..." + + # --dry-run: Don't change files + # --Werror: Exit with non-zero if formatting is needed + # We redirect stderr to a temp file to show you what's wrong + if echo "$FILES" | xargs clang-format --dry-run --Werror 2>/tmp/fmt_err; then + echo "โœจ C++ code is looking good!" + exit 0 + else + echo "------------------------------------------------------" + echo "โŒ ERROR: Python formatting violations found." + echo "Run this script with --apply to fix them." + echo "------------------------------------------------------" + cat /tmp/fmt_err + exit 1 + fi +fi \ No newline at end of file diff --git a/checks/format_ignore.txt b/checks/format_ignore.txt new file mode 100644 index 00000000..c0f78c40 --- /dev/null +++ b/checks/format_ignore.txt @@ -0,0 +1,5 @@ +# Files ignored by the format check +# templates +code_generation/analysis_template.cxx +code_generation/analysis_template_friends.cxx +code_generation/subset_template.cxx \ No newline at end of file diff --git a/checks/python-formatting.sh b/checks/python-formatting.sh index 3f65d7b7..5c1d5927 100644 --- a/checks/python-formatting.sh +++ b/checks/python-formatting.sh @@ -1,16 +1,44 @@ #!/bin/bash -FOUND_ISSUE=0 - -for FILENAME in $(find . -name "*.py"); -do - black --check "$FILENAME" - RETURN_VALUE=$? - if [ $RETURN_VALUE -ne 0 ] - then - black --diff "$FILENAME" 2> /dev/null - FOUND_ISSUE=1 - fi +APPLY_FIXES=false +while [[ "$#" -gt 0 ]]; do + case $1 in + --apply) APPLY_FIXES=true ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac + shift done -exit $FOUND_ISSUE +echo "๐Ÿ” Finding Python files ..." + +# Find tracked python files +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FILES=$(git ls-files | grep -E '\.py$' | grep -vEf "$SCRIPT_DIR/format_ignore.txt") + +if [[ -z "$FILES" ]]; then + echo "No Python files found." + exit 0 +fi + +if [ "$APPLY_FIXES" = true ]; then + echo "๐Ÿ›  Running black to fix formatting..." + # Black formats in-place by default + echo "$FILES" | xargs black + echo "โœ… Python formatting complete." +else + echo "๐Ÿงช Checking Python formatting (Dry Run)..." + + # --check: return exit code 1 if files need formatting + # --diff: show what would change + # --quiet: reduce noise, we only want the diffs/errors + if echo "$FILES" | xargs black --check --diff; then + echo "โœจ Python code is looking good!" + exit 0 + else + echo "------------------------------------------------------" + echo "โŒ ERROR: Python formatting violations found." + echo "Run this script with --apply to fix them." + echo "------------------------------------------------------" + exit 1 + fi +fi \ No newline at end of file diff --git a/checks/run-all-checks.sh b/checks/run-all-checks.sh new file mode 100755 index 00000000..cd3e8581 --- /dev/null +++ b/checks/run-all-checks.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +EXIT_CODE=0 + +APPLY_FIXES="" +while [[ "$#" -gt 0 ]]; do + case $1 in + --apply) APPLY_FIXES=$1;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac + shift +done + +echo "๐Ÿš€ Starting Full Project Linting..." +echo "Location: $SCRIPT_DIR" +echo "----------------------------------------" + +# Function to run sibling scripts +run_sub_script() { + local script_name=$1 + local label=$2 + local full_path="$SCRIPT_DIR/$script_name" + + echo "๐Ÿƒ Running $label..." + + if [ ! -f "$full_path" ]; then + echo "โš ๏ธ Error: $script_name not found in $SCRIPT_DIR" + EXIT_CODE=1 + return + fi + + # Run the script and capture its exit code + bash "$full_path" ${APPLY_FIXES:+"$APPLY_FIXES"} + local status=$? + + if [ $status -eq 0 ]; then + echo "โœ… $label passed." + else + echo "โŒ $label failed (Exit Code: $status)." + EXIT_CODE=1 + fi + echo "----------------------------------------" +} + +# Run all three scripts sequentially +# Note: Even if one fails, the next one will still execute +run_sub_script "cpp-formatting.sh" "C++ Formatting" +run_sub_script "python-formatting.sh" "Python Formatting" +run_sub_script "cmake-formatting.sh" "CMake Formatting" + +# Final Summary for CI/CD +if [ $EXIT_CODE -eq 0 ]; then + echo "๐ŸŽ‰ ALL CHECKS PASSED" + exit 0 +else + echo "โ›” SOME CHECKS FAILED" + echo "Please review the logs above and run with --apply locally." + exit 1 +fi \ No newline at end of file diff --git a/checks/setup_from_tarball.sh b/checks/setup_from_tarball.sh deleted file mode 100755 index 58571a45..00000000 --- a/checks/setup_from_tarball.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -tarball=$1 -checkout_location=$2 -# check if tarball is provided -if [ -z "$tarball" ]; then - echo "ERROR: path to a tarball or an unpacked folder must be provided" - exit 1 -fi -# create the checkout location if it does not exist -if [ ! -d "$checkout_location" ]; then - mkdir -p "$checkout_location" -fi - -if [ -d "$tarball" ]; then - echo "Using tarball folder $tarball" - mkdir temp - cp -r "$tarball" temp/ - tarball=$(realpath "temp/$tarball") -# if tarball is a file, unpack it here -elif [ -f "$tarball" ]; then - echo "Using tarball file $tarball" - mkdir temp - tar -xzf "$tarball" -C temp/ - tarball=$(realpath temp) -else - echo "ERROR: tarball must be a file or a folder" - exit 1 -fi -# go to the checkout location -cd "$checkout_location" -echo "Using temporary tarball copy in $tarball" -# read the commit hashes from the diff folder in the tarball -base_commit=$(cat "$tarball/diff/base_commit_hash.txt") -analysis_commit=$(cat "$tarball/diff/analysis_commit_hash.txt") -analysis_name=$(cat "$tarball/diff/analysis_name.txt") - -# checkout the base repository with the commit hash -git clone --recursive git@github.com:KIT-CMS/CROWN -cd CROWN -git checkout "$base_commit" -# apply the base diff -git apply "$tarball/diff/base_diff.patch" -# setup the analysis with the init script -bash init.sh "$analysis_name" -# checkout the analysis repository with the commit hash -cd "analysis_configurations/$analysis_name" -git checkout "$analysis_commit" -# apply the analysis diff -git apply "$tarball/diff/analysis_diff.patch" -# cleanup the temporary tarball -rm -rf "$tarball" -echo "**************************************************************" -echo "* Setup from tarball finished. You can now run the analysis *" -echo "**************************************************************" diff --git a/cmake/AddDicts.cmake b/cmake/AddDicts.cmake new file mode 100644 index 00000000..b5fa5e9a --- /dev/null +++ b/cmake/AddDicts.cmake @@ -0,0 +1,75 @@ +# Define Paths +set(CACHE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.cache") +set(PERSISTENT_LIB "${CACHE_DIR}/libMyDicts.so") +set(PERSISTENT_PCM "${CACHE_DIR}/libMyDicts_dict_rdict.pcm") +set(PERSISTENT_CC "${CACHE_DIR}/libMyDicts_dict.cc") + +set(SRC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/dictionaries/MyDicts.hxx") +set(SRC_LINKDEF "${CMAKE_CURRENT_SOURCE_DIR}/include/dictionaries/LinkDef.hxx") + +if(NOT EXISTS "${CACHE_DIR}") + file(MAKE_DIRECTORY "${CACHE_DIR}") +endif() + +# Check if Rebuild is Needed +set(NEEDS_REBUILD FALSE) +if(NOT EXISTS "${PERSISTENT_LIB}" + OR NOT EXISTS "${PERSISTENT_PCM}" + OR NOT EXISTS "${PERSISTENT_CC}") + set(NEEDS_REBUILD TRUE) +else() + file(TIMESTAMP "${SRC_HEADER}" SRC_TIME "%s") + file(TIMESTAMP "${PERSISTENT_LIB}" BIN_TIME "%s") + if(${SRC_TIME} GREATER ${BIN_TIME}) + set(NEEDS_REBUILD TRUE) + endif() +endif() + +# Build only if necessary +if(NEEDS_REBUILD) + message( + STATUS "Cache miss: Regenerating ROOT Dictionary and Bootstrap Lib...") + + # Read in root-config flags + execute_process( + COMMAND root-config --cflags + OUTPUT_VARIABLE ROOT_C_FLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process( + COMMAND root-config --libs + OUTPUT_VARIABLE ROOT_L_FLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE) + separate_arguments(C_FLAGS_LIST NATIVE_COMMAND "${ROOT_C_FLAGS}") + separate_arguments(L_FLAGS_LIST NATIVE_COMMAND "${ROOT_L_FLAGS}") + + # Generate directly into the cache directory + execute_process( + COMMAND + rootcling -f ${PERSISTENT_CC} -I${CMAKE_CURRENT_SOURCE_DIR} + -I${CMAKE_CURRENT_SOURCE_DIR}/include -c ${SRC_HEADER} ${SRC_LINKDEF} + WORKING_DIRECTORY ${CACHE_DIR}) + + # Compile the bootstrap .so using the cached .cc + execute_process( + COMMAND + g++ -shared -fPIC -o ${PERSISTENT_LIB} ${PERSISTENT_CC} + -I${CMAKE_CURRENT_SOURCE_DIR}/include ${C_FLAGS_LIST} ${L_FLAGS_LIST}) + + message(STATUS "Dictionary assets cached in .cache/") +else() + message(STATUS "Using cached ROOT Dictionary assets") +endif() + +# Deployment to Build Directory Copy the .so and .pcm so the CMake/Python +# process can load them +file(COPY "${PERSISTENT_LIB}" DESTINATION "${CMAKE_BINARY_DIR}") +file(COPY "${PERSISTENT_PCM}" DESTINATION "${CMAKE_BINARY_DIR}") + +# Build MyDicts library +add_library(MyDicts SHARED ${PERSISTENT_CC}) +target_include_directories(MyDicts PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(MyDicts PUBLIC ROOT::Core ROOT::RIO) + +# Install dictionary and its PCM +install(TARGETS MyDicts DESTINATION ${INSTALLDIR}/lib) +install(FILES "${PERSISTENT_PCM}" DESTINATION ${INSTALLDIR}/lib) diff --git a/cmake/AddOnnxruntime.cmake b/cmake/AddOnnxruntime.cmake index 51f9e0f5..a8043463 100644 --- a/cmake/AddOnnxruntime.cmake +++ b/cmake/AddOnnxruntime.cmake @@ -1,34 +1,67 @@ -# Find ONNXRuntime first check if we have an LCG stack via LCG_VERSION -# environment variable +# Find ONNXRuntime if(DEFINED ENV{LCG_VERSION}) string(REPLACE ":" ";" RUNTIME_PATH "$ENV{LD_LIBRARY_PATH}") message(STATUS "Found LCG stack, using it to find ONNXRuntime") + find_library( ONNX_RUNTIME_LIB_PATH NAMES onnxruntime HINTS ${RUNTIME_PATH}) + if(ONNX_RUNTIME_LIB_PATH) - # get the real path of the library to find the include directory get_filename_component(ONNX_RUNTIME_LIB_PATH ${ONNX_RUNTIME_LIB_PATH} REALPATH) get_filename_component(ONNX_RUNTIME_INCLUDE_PATH ${ONNX_RUNTIME_LIB_PATH}/../../include REALPATH) - message(STATUS "ONNXRuntime include path: ${ONNX_RUNTIME_INCLUDE_PATH}/onnxruntime") + message( + STATUS + "ONNXRuntime include path: ${ONNX_RUNTIME_INCLUDE_PATH}/onnxruntime") include_directories("${ONNX_RUNTIME_INCLUDE_PATH}/onnxruntime") endif() + message(STATUS "ONNXRuntime library path: ${ONNX_RUNTIME_LIB_PATH}") + + # Conda environment (pip-installed onnxruntime) else() - set(ONNXRUNTIME_INCLUDE_DIR "" CACHE FILEPATH "Path to ONNXRUNTIME includes") - message(STATUS "Running in CI, take Onnxruntime from pre-build") - if(NOT EXISTS ${ONNXRUNTIME_INCLUDE_DIR}/include/onnxruntime/core/session/onnxruntime_cxx_api.h) - message(SEND_ERROR "Can't find onnxruntime_cxx_api.h in ${ONNXRUNTIME_INCLUDE_DIR}/include/onnxruntime/core/session") + if(NOT DEFINED ENV{CONDA_PREFIX}) + message(FATAL_ERROR "Neither LCG stack nor Conda environment detected") + endif() + + message(STATUS "Using Conda environment at $ENV{CONDA_PREFIX}") + + # Library is always in conda lib + find_library( + ONNX_RUNTIME_LIB_PATH + NAMES onnxruntime + HINTS $ENV{CONDA_PREFIX}/lib) + + if(NOT ONNX_RUNTIME_LIB_PATH) + message(FATAL_ERROR "onnxruntime shared library not found in Conda env") + endif() + + # Try Conda-style headers first + set(ONNX_RUNTIME_INCLUDE_PATH + $ENV{CONDA_PREFIX}/include/onnxruntime/core/session) + + if(EXISTS ${ONNX_RUNTIME_INCLUDE_PATH}/onnxruntime_cxx_api.h) + message(STATUS "Found Conda-style ONNXRuntime headers") else() - message(STATUS "ONNXRuntime include path: ${ONNXRUNTIME_INCLUDE_DIR}/include/onnxruntime/core/session") - include_directories("${ONNXRUNTIME_INCLUDE_DIR}/include/onnxruntime/core/session") - # lib file is found in ${ONNXRUNTIME_INCLUDE_DIR}/build/Linux/Release - find_library( - ONNX_RUNTIME_LIB_PATH - NAMES onnxruntime - HINTS ${ONNXRUNTIME_INCLUDE_DIR}/build/Linux/Release) + # Fallback: pip-installed headers in site-packages + file(GLOB _ORT_PIP_INCLUDE + $ENV{CONDA_PREFIX}/lib/python*/site-packages/onnxruntime/include) + + if(NOT _ORT_PIP_INCLUDE) + message( + FATAL_ERROR + "onnxruntime headers not found (neither Conda nor pip layout)") + endif() + + list(GET _ORT_PIP_INCLUDE 0 ONNX_RUNTIME_INCLUDE_PATH) + message(STATUS "Found pip-installed ONNXRuntime headers") endif() + + include_directories(${ONNX_RUNTIME_INCLUDE_PATH}) + + message(STATUS "ONNXRuntime include path: ${ONNX_RUNTIME_INCLUDE_PATH}") + message(STATUS "ONNXRuntime library path: ${ONNX_RUNTIME_LIB_PATH}") endif() diff --git a/cmake/AddRoot.cmake b/cmake/AddRoot.cmake index db998fd1..d32e3e12 100644 --- a/cmake/AddRoot.cmake +++ b/cmake/AddRoot.cmake @@ -1,4 +1,5 @@ -find_package(ROOT 6.34 REQUIRED COMPONENTS ROOTVecOps ROOTDataFrame RooFit GenVector Minuit TMVA) +find_package(ROOT 6.36 REQUIRED COMPONENTS ROOTVecOps ROOTDataFrame RooFit + GenVector Minuit TMVA) message(STATUS "") message(STATUS "Found ROOT with following settings:") @@ -20,6 +21,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) message(STATUS "Attach -fconcepts to the compiler flags to silence warnings.") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconcepts") endif() -# require the C++ standard 17 and don't want to fall back to lower +# require the C++ standard 20 and don't want to fall back to lower set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) diff --git a/cmake/Build.cmake b/cmake/Build.cmake index 2da2cf16..203fc816 100644 --- a/cmake/Build.cmake +++ b/cmake/Build.cmake @@ -18,10 +18,7 @@ if(PAYLOADS) DESTINATION ${INSTALLDIR}) endif() -# also copy inish script needed for job tarball -install(FILES init.sh DESTINATION ${INSTALLDIR}) foreach(FILENAME ${FILELIST}) - # STRING(REGEX REPLACE ".cxx" "" TARGET_NAME ${FILENAME}) cmake_path(GET FILENAME RELATIVE_PART RELATIVE_PATH) cmake_path(GET FILENAME FILENAME TARGET_FILENAMENAME) string(REGEX REPLACE ".cxx" "" TARGET_NAME ${TARGET_FILENAMENAME}) @@ -34,24 +31,22 @@ foreach(FILENAME ${FILELIST}) # Add build target message(STATUS "Add build target for file ${FILENAME}.") - # message(STATUS "FULL_PATH: ${FULL_PATH} / TARGET_NAME: ${TARGET_NAME}") - # message(STATUS "Adding header files from - # ${GENERATE_CPP_OUTPUT_DIRECTORY}/${GENERATED_CODEBASE}/include/*") file( GLOB GENERATED_HEADERS LIST_DIRECTORIES true "${GENERATE_CPP_OUTPUT_DIRECTORY}/${GENERATED_CODEBASE}/include/*") file(GLOB GENERATED_CXX_FILES "${GENERATE_CPP_OUTPUT_DIRECTORY}/${GENERATED_CODEBASE}/src/*/*.cxx") - # message(STATUS "GENERATED_HEADERS ${GENERATED_HEADERS}") add_executable(${TARGET_NAME} ${FULL_PATH} ${GENERATED_CXX_FILES}) # Adds a pre-build event to the Target copying the correctionlib.so file into # the /lib folder in the install directory - target_include_directories( - ${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR} ${ROOT_INCLUDE_DIRS} - $ORIGIN/lib/ lib/) + target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR} + ${ROOT_INCLUDE_DIRS}) target_link_libraries( ${TARGET_NAME} + "-Wl,--no-as-needed" # Needed to ensure MyDicts is not 'optimized' away + MyDicts + "-Wl,--as-needed" ROOT::ROOTVecOps ROOT::ROOTDataFrame ROOT::RooFit @@ -68,12 +63,31 @@ foreach(FILENAME ${FILELIST}) PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CORRECTION_LIB_PATH}" ${INSTALLDIR}/lib/libcorrectionlib.so) - # Find shared libraries next to the executable in the /lib folder + + # Add local conda lib path to the executable when available This allows for + # build in local conda env and execution in container + if(DEFINED ENV{CONDA_PREFIX}) + set(CONDA_RPATH "$ENV{CONDA_PREFIX}/lib") + endif() + set_target_properties( - ${TARGET_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE - LINK_FLAGS "-Wl,-rpath,$ORIGIN/lib") - # Add install target, basically just copying the executable around relative to - # CMAKE_INSTALL_PREFIX + ${TARGET_NAME} + PROPERTIES # Allow CMake to manage RPATH for the build and install phases + SKIP_BUILD_RPATH FALSE + BUILD_WITH_INSTALL_RPATH FALSE + # Use $ORIGIN so the binary looks in the 'lib' folder relative to + # itself + # Note: We use \$ORIGIN to prevent CMake from trying to evaluate + # it as a variable + # container conda env path is added for cross-compatibility + INSTALL_RPATH + "\$ORIGIN/lib;${CONDA_RPATH};/opt/conda/envs/env/lib" + # Also tell the binary where to look while still in the build + # directory + BUILD_RPATH + "${CMAKE_BINARY_DIR}/lib;${CONDA_RPATH};/opt/conda/envs/env/lib") + + # copying the executable around relative to CMAKE_INSTALL_PREFIX install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALLDIR}) install( CODE "execute_process(COMMAND ${CMAKE_SOURCE_DIR}/checks/get-diff.sh ${CMAKE_SOURCE_DIR} ${ANALYSIS} ${INSTALLDIR}/diff )" diff --git a/cmake/ConfigureCrownlib.cmake b/cmake/ConfigureCrownlib.cmake index c8fabfb4..6a308365 100644 --- a/cmake/ConfigureCrownlib.cmake +++ b/cmake/ConfigureCrownlib.cmake @@ -2,26 +2,34 @@ include_directories(${CMAKE_SOURCE_DIR}/src) include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/src) -include_directories(${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/include) +include_directories( + ${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/src) +include_directories( + ${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/include) -file(GLOB SOURCES_1 - ${CMAKE_SOURCE_DIR}/src/*.cxx - ${CMAKE_SOURCE_DIR}/src/*/*.cxx) +file(GLOB SOURCES_1 ${CMAKE_SOURCE_DIR}/src/*.cxx + ${CMAKE_SOURCE_DIR}/src/*/*.cxx) -file(GLOB SOURCES_2 +file( + GLOB SOURCES_2 ${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/src/*.cxx - ${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/src/*/*.cxx) + ${CMAKE_SOURCE_DIR}/analysis_configurations/${ANALYSIS}/cpp_addons/src/*/*.cxx +) set(SOURCES ${SOURCES_1} ${SOURCES_2}) -if(BUILD_CROWNLIB_ONLY) - message(STATUS "Building only the CROWNLIB library") +# Function to configure CROWNLIB to avoid code duplication in your if/else +macro(configure_crownlib_target) add_library(CROWNLIB SHARED ${SOURCES}) target_include_directories(CROWNLIB PRIVATE ${CMAKE_SOURCE_DIR} ${ROOT_INCLUDE_DIRS}) target_link_libraries( CROWNLIB + "-Wl,--no-as-needed" # Needed to ensure MyDicts is not 'optimized' away + MyDicts + "-Wl,--as-needed" + ROOT::Core + ROOT::RIO ROOT::ROOTVecOps ROOT::ROOTDataFrame ROOT::RooFit @@ -30,35 +38,26 @@ if(BUILD_CROWNLIB_ONLY) correctionlib nlohmann_json::nlohmann_json ${ONNX_RUNTIME_LIB_PATH}) +endmacro() + +if(BUILD_CROWNLIB_ONLY) + message(STATUS "Building only the CROWNLIB library") + configure_crownlib_target() install(TARGETS CROWNLIB DESTINATION ${INSTALLDIR}/lib) return() endif() -# check if CROWNLIB is already installed -find_library( - CROWNLIB_FOUND CROWNLIB HINTS ${INSTALLDIR}/lib ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/lib) + +# Check for existing CROWNLIB +find_library(CROWNLIB_FOUND CROWNLIB HINTS ${INSTALLDIR}/lib + ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT CROWNLIB_FOUND OR REBUILD_CROWN_LIB) - message(STATUS "CROWNLIB not found, building it") - # CROWNLIB not found, build it - add_library(CROWNLIB SHARED ${SOURCES}) - target_include_directories(CROWNLIB PRIVATE ${CMAKE_SOURCE_DIR} - ${ROOT_INCLUDE_DIRS}) - target_link_libraries( - CROWNLIB - ROOT::ROOTVecOps - ROOT::ROOTDataFrame - ROOT::RooFit - ROOT::GenVector - logging - correctionlib - nlohmann_json::nlohmann_json - ${ONNX_RUNTIME_LIB_PATH}) + message(STATUS "CROWNLIB not found or rebuild requested, building it") + configure_crownlib_target() install(TARGETS CROWNLIB DESTINATION ${INSTALLDIR}/lib) - # needed if compiling with ninja set(CMAKE_BUILD_RPATH ${INSTALLDIR}/lib) else() message(STATUS "Found CROWNLIB in ${CROWNLIB_FOUND}") install(FILES ${CROWNLIB_FOUND} DESTINATION ${INSTALLDIR}/lib) - link_directories(${INSTALLDIR}/lib ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/lib) + link_directories(${INSTALLDIR}/lib ${CMAKE_CURRENT_BINARY_DIR}) endif() diff --git a/cmake/ParseArguments.cmake b/cmake/ParseArguments.cmake index a31b7593..2d14b568 100644 --- a/cmake/ParseArguments.cmake +++ b/cmake/ParseArguments.cmake @@ -46,7 +46,8 @@ else() CACHE STRING "Set default compiler flags for build type Release") find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) - message(STATUS "ccache found at ${CCACHE_FOUND}, using it for compilation") + message( + STATUS "ccache found at ${CCACHE_FOUND}, using it for compilation") set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}") endif() else() diff --git a/code_generation/analysis_template.cxx b/code_generation/analysis_template.cxx index ba15d516..68a312e9 100644 --- a/code_generation/analysis_template.cxx +++ b/code_generation/analysis_template.cxx @@ -1,46 +1,48 @@ -#include "ROOT/RDataFrame.hxx" #include "ROOT/RDFHelpers.hxx" +#include "ROOT/RDataFrame.hxx" #include "RooTrace.h" #include "TStopwatch.h" -#include -#include "include/utility/Logger.hxx" -#include -#include -#include -#include -#include -#include -#include "onnxruntime_cxx_api.h" -#include -#include -#include "include/utility/OnnxSessionManager.hxx" -#include "include/utility/CorrectionManager.hxx" +#include "include/electrons.hxx" +#include "include/embedding.hxx" +#include "include/event.hxx" +#include "include/fatjets.hxx" #include "include/genparticles.hxx" #include "include/htxs.hxx" #include "include/jets.hxx" -#include "include/fatjets.hxx" -#include "include/event.hxx" #include "include/lorentzvectors.hxx" #include "include/met.hxx" #include "include/ml.hxx" +#include "include/muons.hxx" #include "include/pairselection.hxx" -#include "include/tripleselection.hxx" -#include "include/embedding.hxx" #include "include/physicsobjects.hxx" -#include "include/muons.hxx" -#include "include/electrons.hxx" -#include "include/taus.hxx" #include "include/quantities.hxx" #include "include/reweighting.hxx" +#include "include/taus.hxx" #include "include/topreco.hxx" #include "include/triggers.hxx" +#include "include/tripleselection.hxx" +#include "include/utility/CorrectionManager.hxx" +#include "include/utility/Logger.hxx" +#include "include/utility/OnnxSessionManager.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // {INCLUDE_ANALYSISADDONS} // {INCLUDES} -// Choose correct namespace for logging (ROOT 6.34 uses Experimental, 6.36+ does not) -#if ROOT_VERSION_CODE >= ROOT_VERSION(6,36,0) +// Choose correct namespace for logging (ROOT 6.34 uses Experimental, 6.36+ does +// not) +#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 36, 0) namespace ROOTLogNS = ROOT; #else namespace ROOTLogNS = ROOT::Experimental; @@ -51,8 +53,7 @@ int main(int argc, char *argv[]) { // ROOT logging if (debug) { auto verbosity = ROOTLogNS::RLogScopedVerbosity( - ROOT::Detail::RDF::RDFLogChannel(), - ROOTLogNS::ELogLevel::kInfo); + ROOT::Detail::RDF::RDFLogChannel(), ROOTLogNS::ELogLevel::kInfo); RooTrace::verbose(kTRUE); Logger::setLevel(Logger::LogLevel::DEBUG); } else { @@ -68,11 +69,13 @@ int main(int argc, char *argv[]) { "./analysis output.root /path/to/inputfiles/*.root"); return 1; } - // check if CROWN is run from the correct directory, if the folder "data" does not exist, exit + // check if CROWN is run from the correct directory, if the folder "data" + // does not exist, exit if (!std::filesystem::exists("data")) { Logger::get("main")->critical( "CROWN is not run from the correct directory, " - "data folder does not exist. Did you run CROWN from the correct directory?"); + "data folder does not exist. Did you run CROWN from the correct " + "directory?"); return 1; } std::vector input_files; @@ -135,7 +138,7 @@ int main(int argc, char *argv[]) { std::vector> cutReports; // setup output files // {OUTPUT_PATHS} - if (nevents == 0){ + if (nevents == 0) { // {ZERO_EVENTS_FALLBACK} } else { // {CODE_GENERATION} @@ -189,19 +192,19 @@ int main(int argc, char *argv[]) { &analysis_setup_clean); analysis_commit_meta.Fill(); analysis_commit_meta.Write(); - if (nevents != 0){ + if (nevents != 0) { TH1D cutflow; cutflow.SetName("cutflow"); cutflow.SetTitle("cutflow"); - // iterate through the cutflow vector and fill the histogram with the - // .GetPass() values + // iterate through the cutflow vector and fill the histogram with + // the .GetPass() values if (scope_counter >= cutReports.size()) { Logger::get("main")->critical( "Cutflow vector is too small, this should not happen"); return 1; } for (auto cut = cutReports[scope_counter].begin(); - cut != cutReports[scope_counter].end(); cut++) { + cut != cutReports[scope_counter].end(); cut++) { cutflow.SetBinContent( std::distance(cutReports[scope_counter].begin(), cut) + 1, cut->GetPass()); diff --git a/code_generation/analysis_template_friends.cxx b/code_generation/analysis_template_friends.cxx index f67e016c..1a4b3de4 100644 --- a/code_generation/analysis_template_friends.cxx +++ b/code_generation/analysis_template_friends.cxx @@ -1,45 +1,47 @@ -#include "ROOT/RDataFrame.hxx" #include "ROOT/RDFHelpers.hxx" +#include "ROOT/RDataFrame.hxx" #include "RooTrace.h" #include "TStopwatch.h" -#include -#include "include/utility/Logger.hxx" -#include -#include -#include -#include -#include -#include -#include "onnxruntime_cxx_api.h" -#include -#include -#include "include/utility/OnnxSessionManager.hxx" -#include "include/utility/CorrectionManager.hxx" +#include "include/electrons.hxx" +#include "include/embedding.hxx" +#include "include/fatjets.hxx" #include "include/genparticles.hxx" #include "include/htxs.hxx" #include "include/jets.hxx" -#include "include/fatjets.hxx" #include "include/lorentzvectors.hxx" #include "include/met.hxx" #include "include/ml.hxx" +#include "include/muons.hxx" #include "include/pairselection.hxx" -#include "include/embedding.hxx" #include "include/physicsobjects.hxx" -#include "include/muons.hxx" -#include "include/electrons.hxx" -#include "include/taus.hxx" #include "include/quantities.hxx" #include "include/reweighting.hxx" +#include "include/taus.hxx" #include "include/topreco.hxx" #include "include/triggers.hxx" #include "include/tripleselection.hxx" +#include "include/utility/CorrectionManager.hxx" +#include "include/utility/Logger.hxx" +#include "include/utility/OnnxSessionManager.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // {INCLUDE_ANALYSISADDONS} // {INCLUDES} -// Choose correct namespace for logging (ROOT 6.34 uses Experimental, 6.36+ does not) -#if ROOT_VERSION_CODE >= ROOT_VERSION(6,36,0) +// Choose correct namespace for logging (ROOT 6.34 uses Experimental, 6.36+ does +// not) +#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 36, 0) namespace ROOTLogNS = ROOT; #else namespace ROOTLogNS = ROOT::Experimental; @@ -75,12 +77,13 @@ int validate_rootfile(std::string file, std::string &basetree) { nevents += t1->GetEntries(); basetree = "ntuple"; Logger::get("main")->critical("CROWN input_file: {} - {} Events", file, - t1->GetEntries()); + t1->GetEntries()); return nevents; } else { - Logger::get("main")->critical("File {} does not contain a tree " - "named 'Events' or 'ntuple' or 'quantities'", - file); + Logger::get("main")->critical( + "File {} does not contain a tree " + "named 'Events' or 'ntuple' or 'quantities'", + file); return -1; } } @@ -90,8 +93,7 @@ int main(int argc, char *argv[]) { // ROOT logging if (debug) { auto verbosity = ROOTLogNS::RLogScopedVerbosity( - ROOT::Detail::RDF::RDFLogChannel(), - ROOTLogNS::ELogLevel::kInfo); + ROOT::Detail::RDF::RDFLogChannel(), ROOTLogNS::ELogLevel::kInfo); RooTrace::verbose(kTRUE); Logger::setLevel(Logger::LogLevel::DEBUG); } else { diff --git a/code_generation/configuration.py b/code_generation/configuration.py index 1ada2826..e9eb4dd4 100644 --- a/code_generation/configuration.py +++ b/code_generation/configuration.py @@ -394,16 +394,16 @@ def add_shift( if scope in shift.get_scopes(): self._add_available_shift(shift, scope) shift.apply(scope) - self.shifts[scope][ - shift.shiftname - ] = self.resolve_modifiers(shift.get_shift_config(scope)) + self.shifts[scope][shift.shiftname] = ( + self.resolve_modifiers(shift.get_shift_config(scope)) + ) else: self._add_available_shift(shift, scope) shift.apply(self.global_scope) - self.shifts[scope][ - shift.shiftname - ] = self.resolve_modifiers( - shift.get_shift_config(self.global_scope) + self.shifts[scope][shift.shiftname] = ( + self.resolve_modifiers( + shift.get_shift_config(self.global_scope) + ) ) else: for scope in scopes_to_shift: diff --git a/code_generation/friend_trees.py b/code_generation/friend_trees.py index 4300a4a4..84636249 100644 --- a/code_generation/friend_trees.py +++ b/code_generation/friend_trees.py @@ -201,7 +201,21 @@ def _readout_input_root_file( start = time() log.debug(f"Reading quantities information from {input_file}") - ROOT.gSystem.Load(os.path.abspath(__file__), "/maplib.so") # type: ignore + # Load dict parsing lib + lib_path = os.path.abspath("build/libMyDicts.so") + # Physical file check + if not os.path.exists(lib_path): + log.error(f"Missing library: {lib_path}") + # Evaluate ROOT-specific return codes + result = ROOT.gSystem.Load(lib_path) + if result < 0: + err_type = ( + "Version mismatch" + if result == -2 + else "Linker error/Missing dependency" + ) + log.error(f"Load failed ({result}): {err_type} for {lib_path}") + f = ROOT.TFile.Open(input_file) # type: ignore name = "shift_quantities_map" m = f.Get(name) diff --git a/code_generation/maplib.so b/code_generation/maplib.so deleted file mode 100755 index 69c87a58..00000000 Binary files a/code_generation/maplib.so and /dev/null differ diff --git a/code_generation/subset_template.cxx b/code_generation/subset_template.cxx index 11a43cc5..ea4fc502 100644 --- a/code_generation/subset_template.cxx +++ b/code_generation/subset_template.cxx @@ -1,43 +1,45 @@ -#include "ROOT/RDataFrame.hxx" #include "ROOT/RDFHelpers.hxx" +#include "ROOT/RDataFrame.hxx" #include "RooTrace.h" #include "TStopwatch.h" -#include -#include "include/utility/Logger.hxx" -#include -#include -#include -#include -#include -#include -#include "onnxruntime_cxx_api.h" -#include -#include -#include "include/utility/OnnxSessionManager.hxx" -#include "include/utility/CorrectionManager.hxx" +#include "include/electrons.hxx" +#include "include/embedding.hxx" +#include "include/event.hxx" +#include "include/fatjets.hxx" #include "include/genparticles.hxx" #include "include/htxs.hxx" #include "include/jets.hxx" -#include "include/fatjets.hxx" -#include "include/event.hxx" #include "include/lorentzvectors.hxx" #include "include/met.hxx" #include "include/ml.hxx" +#include "include/muons.hxx" #include "include/pairselection.hxx" -#include "include/tripleselection.hxx" -#include "include/embedding.hxx" #include "include/physicsobjects.hxx" -#include "include/muons.hxx" -#include "include/electrons.hxx" -#include "include/taus.hxx" #include "include/quantities.hxx" #include "include/reweighting.hxx" +#include "include/taus.hxx" #include "include/topreco.hxx" #include "include/triggers.hxx" +#include "include/tripleselection.hxx" +#include "include/utility/CorrectionManager.hxx" +#include "include/utility/Logger.hxx" +#include "include/utility/OnnxSessionManager.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // {INCLUDE_ANALYSISADDONS} -ROOT::RDF::RNode {subsetname} (ROOT::RDF::RNode df0, OnnxSessionManager &onnxSessionManager, correctionManager::CorrectionManager &correctionManager) { +ROOT::RDF::RNode {subsetname}(ROOT::RDF::RNode df0, OnnxSessionManager &onnxSessionManager, + correctionManager::CorrectionManager &correctionManager) { // { commands } } diff --git a/code_generation/systematics.py b/code_generation/systematics.py index a0be7241..b106de7e 100644 --- a/code_generation/systematics.py +++ b/code_generation/systematics.py @@ -83,9 +83,9 @@ def __init__( ] = self.expand_producer_dict_keys(ignore_producers) self.producers: TProducerStore = {} self.ignore_producers: TProducerStore = {} - self.shift_config: Dict[ - str, TConfiguration - ] = self.expand_configuration_dict_keys(shift_config) + self.shift_config: Dict[str, TConfiguration] = ( + self.expand_configuration_dict_keys(shift_config) + ) self.scopes: Set[str] = self.determine_scopes(scopes) self.validate() @@ -404,9 +404,9 @@ def __init__( scopes: List of scopes that are affected by the systematic shift. """ super().__init__(name, {}, {}, scopes, {}) - self.quantity_change: Dict[ - NanoAODQuantity, Union[str, NanoAODQuantity] - ] = quantity_change + self.quantity_change: Dict[NanoAODQuantity, Union[str, NanoAODQuantity]] = ( + quantity_change + ) self.quantities: Set[NanoAODQuantity] = set(quantity_change.keys()) def apply(self, scope: str) -> None: diff --git a/data/custom_top_sf/btag_eff/convert_hist_to_corrlib.py b/data/custom_top_sf/btag_eff/convert_hist_to_corrlib.py index 638d7199..efc3c642 100644 --- a/data/custom_top_sf/btag_eff/convert_hist_to_corrlib.py +++ b/data/custom_top_sf/btag_eff/convert_hist_to_corrlib.py @@ -2,7 +2,6 @@ import json import gzip - syst = "" corrs = {} diff --git a/data/custom_top_sf/electron/convert_hist_to_corrlib.py b/data/custom_top_sf/electron/convert_hist_to_corrlib.py index fcbe2e95..1a106712 100644 --- a/data/custom_top_sf/electron/convert_hist_to_corrlib.py +++ b/data/custom_top_sf/electron/convert_hist_to_corrlib.py @@ -2,7 +2,6 @@ import json import gzip - # syst = '' syst = "_syststat" @@ -14,9 +13,9 @@ ) corrs["2016postVFP"] = {} -corrs["2016postVFP"][ - "trigger_filename" -] = "2016postVFP_UL/trig_2016postVFP.root".replace(".root", syst + ".root") +corrs["2016postVFP"]["trigger_filename"] = ( + "2016postVFP_UL/trig_2016postVFP.root".replace(".root", syst + ".root") +) corrs["2017"] = {} corrs["2017"]["trigger_filename"] = "2017_UL/trig_2017.root".replace( diff --git a/data/custom_top_sf/muon/convert_hist_to_corrlib.py b/data/custom_top_sf/muon/convert_hist_to_corrlib.py index e5c48229..01d4e7f4 100644 --- a/data/custom_top_sf/muon/convert_hist_to_corrlib.py +++ b/data/custom_top_sf/muon/convert_hist_to_corrlib.py @@ -2,7 +2,6 @@ import json import gzip - syst = "" # syst = '_combined_syst' diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 44d89d93..9afbf1ae 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -10,77 +10,102 @@ find_package(Sphinx 4.2 REQUIRED) find_package(Python 3.6 REQUIRED COMPONENTS Interpreter) function(find_python_package PYPINAME NAME MIN_VERSION) - execute_process(COMMAND "${Python_EXECUTABLE}" "-c" "import ${NAME}; print(${NAME}.__version__)" - RESULT_VARIABLE PACKAGE_NOT_FOUND - OUTPUT_VARIABLE PACKAGE_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process( + COMMAND "${Python_EXECUTABLE}" "-c" + "import ${NAME}; print(${NAME}.__version__)" + RESULT_VARIABLE PACKAGE_NOT_FOUND + OUTPUT_VARIABLE PACKAGE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(${PACKAGE_NOT_FOUND} EQUAL 1) + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ${PYPINAME} + ${_pip_args}) + execute_process( + COMMAND "${Python_EXECUTABLE}" "-c" + "import ${NAME}; print(${NAME}.__version__)" + RESULT_VARIABLE PACKAGE_NOT_FOUND + OUTPUT_VARIABLE PACKAGE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) if(${PACKAGE_NOT_FOUND} EQUAL 1) - execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ${PYPINAME} ${_pip_args}) - execute_process(COMMAND "${Python_EXECUTABLE}" "-c" "import ${NAME}; print(${NAME}.__version__)" - RESULT_VARIABLE PACKAGE_NOT_FOUND - OUTPUT_VARIABLE PACKAGE_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(${PACKAGE_NOT_FOUND} EQUAL 1) - message(FATAL_ERROR "Failed to import ${PYPINAME} or get version.") - endif() + message(FATAL_ERROR "Failed to import ${PYPINAME} or get version.") endif() - if(PACKAGE_VERSION VERSION_LESS MIN_VERSION) - message(STATUS "The version of Python package ${PYPINAME} is too old (found ${PACKAGE_VERSION}, require at least ${MIN_VERSION}). Starting update installation.") - execute_process(COMMAND ${Python_EXECUTABLE} -m pip install --upgrade ${PYPINAME} ${_pip_args}) - execute_process(COMMAND "${Python_EXECUTABLE}" "-c" "import ${NAME}; print(${NAME}.__version__)" - RESULT_VARIABLE PACKAGE_NOT_FOUND - OUTPUT_VARIABLE PACKAGE_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - endif() - message(STATUS "Found Python package ${PYPINAME} (require ${MIN_VERSION}, found ${PACKAGE_VERSION})") + endif() + if(PACKAGE_VERSION VERSION_LESS MIN_VERSION) + message( + STATUS + "The version of Python package ${PYPINAME} is too old (found ${PACKAGE_VERSION}, require at least ${MIN_VERSION}). Starting update installation." + ) + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install --upgrade + ${PYPINAME} ${_pip_args}) + execute_process( + COMMAND "${Python_EXECUTABLE}" "-c" + "import ${NAME}; print(${NAME}.__version__)" + RESULT_VARIABLE PACKAGE_NOT_FOUND + OUTPUT_VARIABLE PACKAGE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + message( + STATUS + "Found Python package ${PYPINAME} (require ${MIN_VERSION}, found ${PACKAGE_VERSION})" + ) endfunction() find_python_package(breathe breathe 4.35) find_python_package(sphinx_rtd_theme sphinx_rtd_theme 1.2) -# adapted from https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/ +# adapted from +# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/ # Find all headers -file(GLOB_RECURSE HEADERS - ${PROJECT_SOURCE_DIR}/../include/*.hxx - ${PROJECT_SOURCE_DIR}/../include/utility/*.hxx - ${PROJECT_SOURCE_DIR}/../include/*/*.hxx) +file(GLOB_RECURSE HEADERS ${PROJECT_SOURCE_DIR}/../include/*.hxx + ${PROJECT_SOURCE_DIR}/../include/utility/*.hxx + ${PROJECT_SOURCE_DIR}/../include/*/*.hxx) -# Write doxyfile -# Replace variables inside @@ with the current values -set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/../include ${PROJECT_SOURCE_DIR}/../src ${PROJECT_SOURCE_DIR}/../include/utility ${PROJECT_SOURCE_DIR}/../src/utility ) # set in Doxyfile.in +# Write doxyfile Replace variables inside @@ with the current values +set(DOXYGEN_INPUT_DIR + ${PROJECT_SOURCE_DIR}/../include ${PROJECT_SOURCE_DIR}/../src + ${PROJECT_SOURCE_DIR}/../include/utility + ${PROJECT_SOURCE_DIR}/../src/utility) # set in Doxyfile.in list(JOIN DOXYGEN_INPUT_DIR "\" \"" DOXYGEN_INPUT_DIR) set(DOXYGEN_OUTPUT_DIR ${PROJECT_BINARY_DIR}/docs/) # set in Doxyfile.in set(DOXYFILE_IN ${PROJECT_SOURCE_DIR}/Doxyfile.in) set(DOXYFILE_OUT ${PROJECT_BINARY_DIR}/Doxyfile) -configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) # happens at configure time! +configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) # happens at configure + # time! # Create target to generate doxygen docs file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) # Doxygen won't create this for us set(DOXYGEN_INDEX_FILE ${DOXYGEN_BINARY_DIR}/docs/doxygen_index.html) -add_custom_target(Doxygen ALL - DEPENDS ${HEADERS} ${DOXYFILE_OUT} ${DOXYFILE_IN} - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} - COMMENT "Generate doxygen index") +add_custom_target( + Doxygen ALL + DEPENDS ${HEADERS} ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + COMMENT "Generate doxygen index") # now run the update_namespace_docs.py script to add any missing namespace docs -add_custom_command(TARGET Doxygen POST_BUILD - COMMAND ${Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/update_namespace_docs.py --input ${PROJECT_BINARY_DIR} --output ${PROJECT_SOURCE_DIR}/sphinx_source/c_namespaces/ - COMMENT "Updating namespace docs") +add_custom_command( + TARGET Doxygen + POST_BUILD + COMMAND + ${Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/update_namespace_docs.py --input + ${PROJECT_BINARY_DIR} --output + ${PROJECT_SOURCE_DIR}/sphinx_source/c_namespaces/ + COMMENT "Updating namespace docs") if(ret EQUAL "1") - message( FATAL_ERROR "Namespace documentation update failed.") + message(FATAL_ERROR "Namespace documentation update failed.") endif() # Generate sphinx docs from doxygen xml set(SPHINX_SOURCE ${PROJECT_SOURCE_DIR}/sphinx_source/) set(SPHINX_OUTPUT_DIR ${PROJECT_BINARY_DIR}/docs) set(SPHINX_INDEX_FILE ${PROJECT_SOURCE_DIR}/index.html) -add_custom_target(Sphinx ALL - DEPENDS ${HEADERS} - COMMAND ${SPHINX_EXECUTABLE} -b html - # Tell Breathe where to find the Doxygen output - -Dbreathe_projects.CROWN=${DOXYGEN_OUTPUT_DIR}/xml - ${SPHINX_SOURCE} ${SPHINX_OUTPUT_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating documentation with Sphinx") +add_custom_target( + Sphinx ALL + DEPENDS ${HEADERS} + COMMAND + ${SPHINX_EXECUTABLE} -b html + # Tell Breathe where to find the Doxygen output + -Dbreathe_projects.CROWN=${DOXYGEN_OUTPUT_DIR}/xml ${SPHINX_SOURCE} + ${SPHINX_OUTPUT_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating documentation with Sphinx") add_dependencies(Sphinx Doxygen) diff --git a/docs/cmake/FindSphinx.cmake b/docs/cmake/FindSphinx.cmake index 93c99f65..353a2c38 100644 --- a/docs/cmake/FindSphinx.cmake +++ b/docs/cmake/FindSphinx.cmake @@ -1,11 +1,11 @@ -#Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") +# Look for an executable called sphinx-build +find_program( + SPHINX_EXECUTABLE + NAMES sphinx-build + DOC "Path to sphinx-build executable") include(FindPackageHandleStandardArgs) -#Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) +# Handle standard arguments to find_package like REQUIRED and QUIET +find_package_handle_standard_args( + Sphinx "Failed to find sphinx-build executable" SPHINX_EXECUTABLE) diff --git a/docs/sphinx_source/changelog.rst b/docs/sphinx_source/changelog.rst index 66456c68..aefbc36f 100644 --- a/docs/sphinx_source/changelog.rst +++ b/docs/sphinx_source/changelog.rst @@ -16,7 +16,7 @@ Sept. 2023 - Version 0.3.0 Feb. 2023 * Added support for the generation of friend trees. For more details, check :ref:`FriendTree Generation`. -* Added documentation on Ntuple and friend production via KingMaker. For more details, check :ref:`Workflow Management`. +* Added documentation on Ntuple and friend production via KingMaker. For more details, check :ref:`Kingmaker Workflow Management`. Jan. 2023 diff --git a/docs/sphinx_source/friend_trees.rst b/docs/sphinx_source/friend_trees.rst index 177f881d..be95cacf 100644 --- a/docs/sphinx_source/friend_trees.rst +++ b/docs/sphinx_source/friend_trees.rst @@ -43,7 +43,7 @@ A FriendTree is generated using a FriendTreeConfiguration. Such a configuration -The recommended way of producing FriendTrees is to use a workflow tool, that manages the submission of jobs, generation of tarballs and organizing the output. One possible workflow tool choice is KingMaker (https://github.com/KIT-CMS/KingMaker). A more detailed description of the KingMaker workflow can be found in :ref:`Workflow Management`. +The recommended way of producing FriendTrees is to use a workflow tool, that manages the submission of jobs, generation of tarballs and organizing the output. One possible workflow tool choice is KingMaker (https://github.com/KIT-CMS/KingMaker). A more detailed description of the KingMaker workflow can be found in :ref:`Kingmaker Workflow Management`. Writing a FriendTreeConfiguration --------------------------------- diff --git a/docs/sphinx_source/index.rst b/docs/sphinx_source/index.rst index ca45af5c..89e3829a 100644 --- a/docs/sphinx_source/index.rst +++ b/docs/sphinx_source/index.rst @@ -7,7 +7,7 @@ The **C** ++-based **RO** OT **W** orkflow for **N** -tuples (CROWN) is a fast n To get started with CROWN, go here: :ref:`Getting started`. .. note:: - To get started with an ntuple production workflow that uses CROWN, go here: :ref:`Workflow Management`. + To get started with an ntuple production workflow that uses CROWN, go here: :ref:`Kingmaker Workflow Management`. .. note:: To read about recent changes and new features, go here: :ref:`changelog`. diff --git a/docs/sphinx_source/introduction.rst b/docs/sphinx_source/introduction.rst index 19ca237e..88cdb96b 100644 --- a/docs/sphinx_source/introduction.rst +++ b/docs/sphinx_source/introduction.rst @@ -34,19 +34,19 @@ First, clone the Repository git clone --recurse-submodules git@github.com:KIT-CMS/CROWN.git -and source the current LCG stack +and set up the container environment .. code-block:: console source init.sh -After this, the framework is installed, but without any analysis, other than the example analysis. If you want to set up a specific analysis, you can do so by adding the name of the analysis to your ``init.sh`` command. So e.g. to set up the `tau` Analysis, you can do so by running +After this, the framework is ready to use, but without any analysis, other than the example analysis. If you want to set up a specific analysis, you can do so by adding the ``-a``/``--analysis`` argument and the name of the analysis to your ``init.sh`` command. So e.g. to set up the `tau` Analysis, you can do so by running .. code-block:: console - source init.sh tau + source init.sh -a tau -The following list shows all currently available analyses that can be set up. If you want to include your own analysis, it needs to be added to the ``init.sh`` script. +The following list shows all currently available analyses that can be set up. .. list-table:: Available Analyses Configurations for CROWN :widths: 25 150 @@ -69,6 +69,20 @@ The following list shows all currently available analyses that can be set up. If * - ``haa`` - https://github.com/KIT-CMS/HaaAnalysis-CROWN +The same list is also provided by the ``-l``/``--list`` argument of the ``init.sh`` script. +If you want to include your own analysis, it needs to be added to the ``init.sh`` script. + +It is also possible to use an alternative container instead of the default (``/cvmfs/unpacked.cern.ch/registry.hub.docker.com/kingmakerimages/kingmaker_standalone:V1``), by using the ``-c``/``--container`` argument. + +.. code-block:: console + + source init.sh -c "" + +If the container argument is set to ``none``, it is expected that you currently are in an environment where the framework can be used without a container, e.g. a local machine with all dependencies installed or a conda environment. +Additionally, the container can be set to ``lcg``, which will use the LCG stack environment instead of the default container. + +Finally, with the ``-d``/``--dry-run`` argument the analysis configuration is cloned, but the container is not started. + Running the framework ********************** @@ -111,9 +125,7 @@ Compile the executable using make install -j 8 -The recommended build system is using regular UNIX build files, however, as an additional option, the ninja build system (https://ninja-build.org/) can be used for CROWN. To use ninja, set :code:`export CMAKE_GENERATOR="Ninja"` in the :code:`init.sh` as env variable, and then use the :code:`ninja install -j 8` command to compile the executable. Since CROWN profits from the parallelization of the build process, the number of threads can and should be set using the :code:`-j` option. - - +Since CROWN profits from the parallelization of the build process, the number of threads can and should be set using the :code:`-j` option. After the compilation, the CROWN executable can be found in the :code:`build/bin` folder. The executable can be used via a single output file followed by an arbitrary number of input files. .. code-block:: console diff --git a/docs/sphinx_source/kingmaker.rst b/docs/sphinx_source/kingmaker.rst index 3109f635..6fe03583 100644 --- a/docs/sphinx_source/kingmaker.rst +++ b/docs/sphinx_source/kingmaker.rst @@ -1,4 +1,4 @@ -Workflow Management +Kingmaker Workflow Management =================== KingMaker is a workflow management for producing ntuples with the CROWN framework. The workflow management is based on law (https://github.com/riga/law), which uses luigi (https://github.com/spotify/luigi) as the backend. Kingmaker is used to orchestrate the production of ntuples and friend trees for the CROWN framework. The workflow is designed to be flexible and can be adapted to different analyses. Kingmaker takes care of building all required CROWN executables, submitting jobs to a batch system and writing the output to a remote storage. On top of that, Kingmaker can be used to generate FriendTrees, which can be used to store additional information to extend the ntuples. A sample manager is provided to manage the samples and keep track of the individual input files that have to be processed. @@ -13,7 +13,7 @@ Setup .. code-block:: bash - git clone git@github.com:KIT-CMS/KingMaker.git + git clone --recurse-submodules git@github.com:KIT-CMS/KingMaker.git cd KingMaker source setup.sh @@ -21,19 +21,19 @@ This should install all required packages and set up the environment. In additio The setup script has also additional options: .. code-block:: bash - + Usage: source setup.sh [options] Options: - -a, --analysis ANALYSIS Specify the analysis workflow to use + -w, --workflow WORKFLOW Specify the workflow to use [default: KingMaker] - -c, --crown-analysis NAME Specify CROWN analysis to check out (only with KingMaker workflow) + -a, --analysis NAME Specify CROWN analysis to check out (only with KingMaker workflow) [default: plain CROWN] Available analyses: https://crown.readthedocs.io/en/latest/introduction.html#id1 - -e, --env-path PATH Specify custom environment path + -e, --env-path PATH Specify custom environment path [default: auto-detected] - -l, --list List available workflows - -h, --help Show this help message + -l, --list List available workflows + -h, --help Show this help message It is possible that the session failes to connect to the remote scheduler after some time. After ``source setup.sh`` is run, the scheduler is running on a random port, which is stored in the ``LUIGIPORT`` environment variable. @@ -305,7 +305,7 @@ The ``KingMaker_luigi.cfg`` file contains the configuration of the different tas wlcg_path = root://cmsdcache-kit-disk.gridka.de//store/user/${USER}/CROWN/ntuples/ htcondor_accounting_group = cms.higgs htcondor_remote_job = True - htcondor_universe = docker + htcondor_universe = container transfer_logs = True local_scheduler = True tolerance = 0.00 @@ -352,11 +352,11 @@ For a more complete description of the different options, please refer to the ov Local debugging ----------------------- -The compiled executables that are used in the submitted jobs can be found in the ``tarballs//`` directories. +The compiled executables that are used in the submitted jobs can be found in the ``tarballs//`` directories. All executables can be tested locally: -1. Change to the directory with the executable (`tarballs//CROWN*/`, depending on which step you are running). -2. Source the ``init.sh`` script. +1. Run the ``CROWN/init.sh`` script, which puts you into the container environment. +2. Change to the directory with the executable (`tarballs//CROWN*/`, depending on which step you are running). 3. Run the executable with the required arguments. The exact arguments required to call the executable depend on the type: @@ -371,21 +371,17 @@ The executables work with remote input paths/files, but the path to the output f # Ntuples cd tarballs//CROWN__/ - source init.sh ./__ ... - # Friends cd tarballs//CROWNFriends_____ # Where `mapped_friend_name` is either directly set via `--friend-name`, or set in the `--friend-mapping` for the `friend_config`. - source init.sh - ./___ + ./___ # MultiFriends (Friends with Friends as inputs) cd tarballs//CROWNFriends_____ # Where `multi_friend_name` is set via `--friend-name`. - source init.sh ./___ ... For the command provided in :ref:`Production of friend trees with additional friends as input`, this turns into: @@ -394,18 +390,15 @@ For the command provided in :ref:`Production of friend trees with additional fri # Ntuples cd tarballs/test_production_v1/CROWN_template_analysis_template_config/ - source init.sh ./template_config_data_2018 ... # Friends cd tarballs/test_production_v1/CROWNFriends_template_analysis_template_friend_config_test_friend_v1_data_2018/ - source init.sh ./template_friend_config_data_2018_mm # MultiFriends (Friends with Friends as inputs) cd tarballs/test_production_v1/CROWNFriends_template_analysis_template_multifriend_config_test_multifriend_v1_data_2018/ - source init.sh ./template_multifriend_config_data_2018_mm -If further investigation is needed, a local compilation of the CROWN config is recommended as described in :ref:`Running the framework` +If further investigation is needed, a local compilation of the CROWN config is recommended as described in :ref:`Running the framework` with optionally activating `-DDEBUG`. diff --git a/include/defaults.hxx b/include/defaults.hxx index 3dd8737d..f8bbc685 100644 --- a/include/defaults.hxx +++ b/include/defaults.hxx @@ -7,9 +7,9 @@ const int default_int = -10; const float default_float = -10.0; -// casting this default UChar_t to an int results in a value of 246 -// which should still be out of range for the usual use cases -const UChar_t default_uchar = -10; +// casting this default UChar_t to an int results in a value of 246 +// which should still be out of range for the usual use cases +const UChar_t default_uchar = -10; const bool default_bool = false; const auto default_lorentzvector = ROOT::Math::PtEtaPhiMVector(0., 0., 0., 0.); diff --git a/include/dictionaries/LinkDef.hxx b/include/dictionaries/LinkDef.hxx new file mode 100644 index 00000000..c4cdc9a9 --- /dev/null +++ b/include/dictionaries/LinkDef.hxx @@ -0,0 +1,11 @@ +#ifdef __CINT__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ nestedclasses; + +#pragma link C++ class std::map < std::string, std::vector < std::string>> + ; +#pragma link C++ class std::map < std::string, std::map < std::string, \ + std::vector < std::string>>> + \ + ; +#endif \ No newline at end of file diff --git a/include/dictionaries/MyDicts.hxx b/include/dictionaries/MyDicts.hxx new file mode 100644 index 00000000..1e0a7851 --- /dev/null +++ b/include/dictionaries/MyDicts.hxx @@ -0,0 +1,16 @@ +#ifndef MYDICTS_H +#define MYDICTS_H + +#include +#include +#include + +#ifdef __CLING__ +// The '+' at the end tells ROOT to enable streamer/I/O support +#pragma link C++ class std::map < std::string, std::vector < std::string>> + ; +#pragma link C++ class std::map < std::string, std::map < std::string, \ + std::vector < std::string>>> + \ + ; +#endif + +#endif \ No newline at end of file diff --git a/include/electrons.hxx b/include/electrons.hxx index 18b3c5c4..ec9e8da1 100644 --- a/include/electrons.hxx +++ b/include/electrons.hxx @@ -1,6 +1,8 @@ #ifndef GUARD_ELECTRONS_H #define GUARD_ELECTRONS_H +#include "utility/CorrectionManager.hxx" + namespace physicsobject { namespace electron { @@ -11,30 +13,25 @@ PtCorrectionMC(ROOT::RDF::RNode df, const std::string &eta, const std::string &seed_gain, const std::string &es_resolution_up, const std::string &es_resolution_down, - const std::string &es_file, - const std::string &es_name, + const std::string &es_file, const std::string &es_name, const std::string &era, - const std::string &variation); // for Run 2 + const std::string &variation); // for Run 2 ROOT::RDF::RNode PtCorrectionMC(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, const std::string &outputname, const std::string &pt, - const std::string &eta, - const std::string &delta_eta_sc, - const std::string &r9, - const std::string &event_seed, - const std::string &sf_file, - const std::string &sf_name, - const std::string &variation); // for Run 3 + const std::string &eta, const std::string &delta_eta_sc, + const std::string &r9, const std::string &event_seed, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation); // for Run 3 ROOT::RDF::RNode PtCorrectionData(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &delta_eta_sc, - const std::string &seed_gain, - const std::string &r9, const std::string &run, - const std::string &sf_file, - const std::string &sf_name); // for Run 3 + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &delta_eta_sc, + const std::string &seed_gain, const std::string &r9, + const std::string &run, const std::string &sf_file, + const std::string &sf_name); // for Run 3 ROOT::RDF::RNode VetoECALGap(ROOT::RDF::RNode df, const std::string &outputname, const std::string &eta, const std::string &delta_eta_sc, @@ -52,17 +49,18 @@ namespace scalefactor { ROOT::RDF::RNode Id(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correctionManager, const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &phi, - const std::string &era, - const std::string &wp, const std::string &sf_file, - const std::string &sf_name, const std::string &variation); -ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &trigger_flag, - const std::string &era, const std::string &path_id_name, + const std::string &eta, const std::string &phi, + const std::string &era, const std::string &wp, const std::string &sf_file, const std::string &sf_name, const std::string &variation); +ROOT::RDF::RNode +Trigger(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &trigger_flag, + const std::string &era, const std::string &path_id_name, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation); } // end namespace scalefactor } // end namespace electron } // end namespace physicsobject diff --git a/include/embedding.hxx b/include/embedding.hxx index c1a926b2..49a576a6 100644 --- a/include/embedding.hxx +++ b/include/embedding.hxx @@ -1,25 +1,25 @@ #ifndef GUARD_EMBEDDING_H #define GUARD_EMBEDDING_H +#include "utility/CorrectionManager.hxx" + namespace embedding { namespace scalefactor { ROOT::RDF::RNode SelectionTrigger(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt_1, const std::string &eta_1, - const std::string &pt_2, const std::string &eta_2, - const std::string &sf_file, - const std::string &sf_name); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt_1, + const std::string &eta_1, const std::string &pt_2, + const std::string &eta_2, const std::string &sf_file, + const std::string &sf_name); ROOT::RDF::RNode SelectionId(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &eta, - const std::string &sf_file, - const std::string &sf_name); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name); } // end namespace scalefactor namespace muon { @@ -27,10 +27,9 @@ namespace muon { ROOT::RDF::RNode Scalefactor(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &output, - const std::string &pt, const std::string &eta, - const std::string &sf_file, const std::string &sf_name, - const std::string correction_type, + const std::string &output, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name, const std::string correction_type, const float &extrapolation_factor = 1.0); } // end namespace muon @@ -51,10 +50,9 @@ PtCorrection(ROOT::RDF::RNode df, ROOT::RDF::RNode Scalefactor(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &output, - const std::string &pt, const std::string &eta, - const std::string &sf_file, const std::string &sf_name, - const std::string correction_type, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name, const std::string correction_type, const float &extrapolation_factor = 1.0); } // end namespace electron @@ -71,14 +69,11 @@ namespace scalefactor { ROOT::RDF::RNode Id_vsJet_lt(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::vector &selected_dms, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::vector &selected_dms, const std::string &wp, + const std::string &vsele_wp, const std::string &sf_dependence, const std::string &sf_vsjet_tau20to25, const std::string &sf_vsjet_tau25to30, const std::string &sf_vsjet_tau30to35, diff --git a/include/event.hxx b/include/event.hxx index 5b834f98..226f6780 100644 --- a/include/event.hxx +++ b/include/event.hxx @@ -1,12 +1,12 @@ #ifndef GUARD_EVENT_H #define GUARD_EVENT_H -#include "../include/defaults.hxx" -#include "../include/utility/CorrectionManager.hxx" -#include "../include/utility/Logger.hxx" -#include "../include/utility/utility.hxx" #include "ROOT/RDataFrame.hxx" #include "ROOT/RVec.hxx" +#include "defaults.hxx" +#include "utility/CorrectionManager.hxx" +#include "utility/Logger.hxx" +#include "utility/utility.hxx" #include #include @@ -66,7 +66,7 @@ inline auto CombineFlags(ROOT::RDF::RNode df, const std::string &outputname, namespace quantity { /** - * @brief This function creates a flag column based on a quantity. + * @brief This function creates a flag column based on a quantity. * The flag is set to `true` if the quantity value is even and `false` * if it is odd. This can be useful for splitting datasets into two subsets. * @@ -79,12 +79,13 @@ namespace quantity { * @return a dataframe with the new flag column */ template -inline ROOT::RDF::RNode -EvenOddFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity) { - return df.Define(outputname, [](const T &quantity) { - return (quantity % 2 == 0) ? true : false; - }, {quantity}); +inline ROOT::RDF::RNode EvenOddFlag(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &quantity) { + return df.Define( + outputname, + [](const T &quantity) { return (quantity % 2 == 0) ? true : false; }, + {quantity}); } /** @@ -105,7 +106,7 @@ EvenOddFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode MinFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = value >= threshold; @@ -132,7 +133,7 @@ MinFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode AbsMinFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = abs(value) >= threshold; @@ -159,7 +160,7 @@ AbsMinFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode MaxFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = value < threshold; @@ -186,7 +187,7 @@ MaxFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode AbsMaxFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = abs(value) < threshold; @@ -213,7 +214,7 @@ AbsMaxFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode EqualFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = value == threshold; @@ -240,7 +241,7 @@ EqualFlag(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode AbsEqualFlag(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &quantity, const T &threshold) { + const std::string &quantity, const T &threshold) { return df.Define(outputname, [threshold](const T &value) { bool flag = abs(value) == threshold; @@ -298,7 +299,7 @@ inline ROOT::RDF::RNode Define(ROOT::RDF::RNode df, * vector * @param quantity name of the input column whose size determines the length of * the random vector - * @param seed seed value for the random number generator, if not set the answer + * @param seed seed value for the random number generator, if not set the answer * to everything is used as default `42` * * @return a dataframe with the new column @@ -317,15 +318,11 @@ GenerateRandomVector(ROOT::RDF::RNode df, const std::string &outputname, {quantity}); } -ROOT::RDF::RNode -GenerateSeed( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lumi, - const std::string &run, - const std::string &event, - const UInt_t &master_seed = 42 -); +ROOT::RDF::RNode GenerateSeed(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &lumi, const std::string &run, + const std::string &event, + const UInt_t &master_seed = 42); /** * @brief This function creates a new column in the dataframe by applying @@ -351,7 +348,7 @@ inline ROOT::RDF::RNode Negate(ROOT::RDF::RNode df, * specified in a collection index. The order of the output values reflects the * order of the indices. The function uses `ROOT::VecOps::Take` internally, * leading to the following behavior: - * + * * ```C++ * auto values = ROOT::RVec({0.1, 0.2, 0.3, 0.4}); * auto index = ROOT::RVec({2, 3, 1}); @@ -359,11 +356,11 @@ inline ROOT::RDF::RNode Negate(ROOT::RDF::RNode df, * result * // (ROOT::VecOps::RVec) {0.3, 0.4, 0.2} * ``` - * + * * The column `index_vector` must contain the indices for which values * should be extracted, and the `quantity` column must contain the values * of the quantity. - * + * * Note that `T` is the type of the values stored in the `RVec` containers in * the `quantity` column, e.g., if the column has type `RVec`, you * must use `T = float`. @@ -379,30 +376,20 @@ inline ROOT::RDF::RNode Negate(ROOT::RDF::RNode df, * @note If the index is out of range, a default value of type `T` is returned. */ template -inline ROOT::RDF::RNode Take( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &quantity, - const std::string &index_vector -) { - auto take = [] ( - const ROOT::RVec &quantity, - const ROOT::RVec &index_vector - ) { +inline ROOT::RDF::RNode Take(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &quantity, + const std::string &index_vector) { + auto take = [](const ROOT::RVec &quantity, + const ROOT::RVec &index_vector) { Logger::get("event::quantity::Take") ->debug("Taking quantity {} at indices {}", quantity, index_vector); auto result = ROOT::VecOps::Take(quantity, index_vector); - Logger::get("event::quantity::Take") - ->debug("Result {}", result); + Logger::get("event::quantity::Take")->debug("Result {}", result); return result; }; - return df.Define( - outputname, - take, - {quantity, index_vector} - ); + return df.Define(outputname, take, {quantity, index_vector}); } /** @@ -422,31 +409,32 @@ inline ROOT::RDF::RNode Take( template inline ROOT::RDF::RNode Get(ROOT::RDF::RNode df, const std::string &outputname, const std::string &quantity, const int &index) { - return df.Define(outputname, - [index](const ROOT::RVec &quantity) { - T result = default_value(); - - try { - result = quantity.at(index); - } catch (const std::out_of_range &e) { - Logger::get("event::quantity::Get") - ->debug( - "Index not found, returning dummy value!"); - } - // the static_cast is used because some types of nanoAOD - // branches changed from Int_t to UChar_t for nanoAOD - // versions > 9 - if constexpr (std::is_same::value || std::is_same::value) { - int cast_result = static_cast(result); - Logger::get("event::quantity::Get") - ->debug("Returning UChar_t/Short_t quantity as int: {}", - cast_result); - return cast_result; - } else { - return result; - } - }, - {quantity}); + return df.Define( + outputname, + [index](const ROOT::RVec &quantity) { + T result = default_value(); + + try { + result = quantity.at(index); + } catch (const std::out_of_range &e) { + Logger::get("event::quantity::Get") + ->debug("Index not found, returning dummy value!"); + } + // the static_cast is used because some types of nanoAOD + // branches changed from Int_t to UChar_t for nanoAOD + // versions > 9 + if constexpr (std::is_same::value || + std::is_same::value) { + int cast_result = static_cast(result); + Logger::get("event::quantity::Get") + ->debug("Returning UChar_t/Short_t quantity as int: {}", + cast_result); + return cast_result; + } else { + return result; + } + }, + {quantity}); } /** @@ -470,33 +458,34 @@ inline ROOT::RDF::RNode Get(ROOT::RDF::RNode df, const std::string &outputname, const std::string &quantity, const std::string &index_vector, const int &position) { - return df.Define(outputname, - [position](const ROOT::RVec &quantity, - const ROOT::RVec &indices) { - T result = default_value(); - - try { - const int index = indices.at(position); - result = quantity.at(index); - } catch (const std::out_of_range &e) { - Logger::get("event::quantity::Get") - ->debug( - "Index not found, returning dummy value!"); - } - // the static_cast is used because some types of nanoAOD - // branches changed from Int_t to UChar_t for nanoAOD - // versions > 9 - if constexpr (std::is_same::value || std::is_same::value) { - int cast_result = static_cast(result); - Logger::get("event::quantity::Get") - ->debug("Returning UChar_t/Short_t quantity as int: {}", - cast_result); - return cast_result; - } else { - return result; - } - }, - {quantity, index_vector}); + return df.Define( + outputname, + [position](const ROOT::RVec &quantity, + const ROOT::RVec &indices) { + T result = default_value(); + + try { + const int index = indices.at(position); + result = quantity.at(index); + } catch (const std::out_of_range &e) { + Logger::get("event::quantity::Get") + ->debug("Index not found, returning dummy value!"); + } + // the static_cast is used because some types of nanoAOD + // branches changed from Int_t to UChar_t for nanoAOD + // versions > 9 + if constexpr (std::is_same::value || + std::is_same::value) { + int cast_result = static_cast(result); + Logger::get("event::quantity::Get") + ->debug("Returning UChar_t/Short_t quantity as int: {}", + cast_result); + return cast_result; + } else { + return result; + } + }, + {quantity, index_vector}); } /** @@ -526,110 +515,124 @@ inline ROOT::RDF::RNode Get(ROOT::RDF::RNode df, const std::string &outputname, * * @tparam T type of the input gen. jet column values * @param df input dataframe - * @param outputname name of the output column containing the gen. jet quantity value - * @param genjet_quantity name of the column containing the gen. jet quantity vector - * @param jet_genjet_index name of the column containing the association (via index) - * between the jet and the gen. jet collection - * @param index_vector name of the column containing the vector with the relevant - * jet indices - * @param position position in the index vector that specifies which jet in the + * @param outputname name of the output column containing the gen. jet quantity + * value + * @param genjet_quantity name of the column containing the gen. jet quantity + * vector + * @param jet_genjet_index name of the column containing the association (via + * index) between the jet and the gen. jet collection + * @param index_vector name of the column containing the vector with the + * relevant jet indices + * @param position position in the index vector that specifies which jet in the * jet vector should be used to get its associated gen. jet quantity * * @return a dataframe with the new column */ template -ROOT::RDF::RNode GetGenJetForJet( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &genjet_quantity, - const std::string &jet_genjet_index, - const std::string &index_vector, - const int &position) { +ROOT::RDF::RNode +GetGenJetForJet(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &genjet_quantity, + const std::string &jet_genjet_index, + const std::string &index_vector, const int &position) { // In nanoAODv12 the types of jet indices were changed to Short_t // For v9 compatibility a type casting is applied - auto [df1, jet_genjet_index_column] = utility::Cast, ROOT::RVec>( - df, jet_genjet_index+"_v12", "ROOT::VecOps::RVec", jet_genjet_index); - - return df1.Define(outputname, + auto [df1, jet_genjet_index_column] = + utility::Cast, ROOT::RVec>( + df, jet_genjet_index + "_v12", "ROOT::VecOps::RVec", + jet_genjet_index); + + return df1.Define( + outputname, [position](const ROOT::RVec &quantity, const ROOT::RVec &jet_genjet_idx_v12, const ROOT::RVec &indices) { - auto jet_genjet_idx = static_cast>(jet_genjet_idx_v12); + auto jet_genjet_idx = + static_cast>(jet_genjet_idx_v12); const int jet_index = indices.at(position); const int genjet_index = jet_genjet_idx.at(jet_index, -1); - + T result = quantity.at(genjet_index, default_value()); - Logger::get("event::quantity::GetGenJetForJet")->debug( - " Retrieved gen. jet quantity value {} for jet index {}", - result, jet_index - ); + Logger::get("event::quantity::GetGenJetForJet") + ->debug( + " Retrieved gen. jet quantity value {} for jet index {}", + result, jet_index); return result; }, {genjet_quantity, jet_genjet_index_column, index_vector}); } -/** - * @brief This function gets the gen. jet quantity for a given object. All objects - * are usually also reconstructed as jets. This function finds the corresponding jet - * and the associated gen. jet via indices that are present in nanoAODs. +/** + * @brief This function gets the gen. jet quantity for a given object. All + * objects are usually also reconstructed as jets. This function finds the + * corresponding jet and the associated gen. jet via indices that are present in + * nanoAODs. * * If the generator-level jet cannot be accessed, the function returns a * default value. * * @tparam T type of the input gen. jet column values * @param df input dataframe - * @param outputname name of the output column containing the gen. jet quantity value - * @param genjet_quantity name of the column containing the gen. jet quantity vector - * @param jet_genjet_index name of the column containing the association (via index) - * between the jet and the gen. jet collection - * @param object_jet_index name of the column containing the association (via index) - * between the object and the jet collection - * @param object_index_vector name of the column containing the vector with the relevant - * object indices - * @param position position in the index vector that specifies which object in the - * object vector should be used to get its associated gen. jet quantity + * @param outputname name of the output column containing the gen. jet quantity + * value + * @param genjet_quantity name of the column containing the gen. jet quantity + * vector + * @param jet_genjet_index name of the column containing the association (via + * index) between the jet and the gen. jet collection + * @param object_jet_index name of the column containing the association (via + * index) between the object and the jet collection + * @param object_index_vector name of the column containing the vector with the + * relevant object indices + * @param position position in the index vector that specifies which object in + * the object vector should be used to get its associated gen. jet quantity * * @return a dataframe with the new column */ template ROOT::RDF::RNode GetGenJetForObject(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &genjet_quantity, - const std::string &jet_genjet_index, - const std::string &object_jet_index, - const std::string &object_index_vector, - const int &position) { + const std::string &outputname, + const std::string &genjet_quantity, + const std::string &jet_genjet_index, + const std::string &object_jet_index, + const std::string &object_index_vector, + const int &position) { // In nanoAODv12 the types of jet indices were changed to Short_t // For v9 compatibility a type casting is applied - auto [df1, jet_genjet_index_column] = utility::Cast, ROOT::RVec>( - df, jet_genjet_index+"_v12", "ROOT::VecOps::RVec", jet_genjet_index); - auto [df2, object_jet_index_column] = utility::Cast, ROOT::RVec>( - df1, object_jet_index+"_v12", "ROOT::VecOps::RVec", object_jet_index); - return df2.Define(outputname, + auto [df1, jet_genjet_index_column] = + utility::Cast, ROOT::RVec>( + df, jet_genjet_index + "_v12", "ROOT::VecOps::RVec", + jet_genjet_index); + auto [df2, object_jet_index_column] = + utility::Cast, ROOT::RVec>( + df1, object_jet_index + "_v12", "ROOT::VecOps::RVec", + object_jet_index); + return df2.Define( + outputname, [position](const ROOT::RVec &quantity, - const ROOT::RVec &jet_genjet_idx_v12, - const ROOT::RVec &obj_jet_idx_v12, - const ROOT::RVec &obj_indices) { - auto jet_genjet_idx = static_cast>(jet_genjet_idx_v12); + const ROOT::RVec &jet_genjet_idx_v12, + const ROOT::RVec &obj_jet_idx_v12, + const ROOT::RVec &obj_indices) { + auto jet_genjet_idx = + static_cast>(jet_genjet_idx_v12); auto obj_jet_idx = static_cast>(obj_jet_idx_v12); const int obj_index = obj_indices.at(position); const int jet_index = obj_jet_idx.at(obj_index, -1); const int genjet_index = jet_genjet_idx.at(jet_index, -1); T result = quantity.at(genjet_index, default_value()); - Logger::get("event::quantity::GetGenJetForObject")->debug( - " Retrieved gen. jet quantity value {} for object index {}", - result, obj_index - ); + Logger::get("event::quantity::GetGenJetForObject") + ->debug(" Retrieved gen. jet quantity value {} for object " + "index {}", + result, obj_index); return result; }, - {genjet_quantity, jet_genjet_index_column, object_jet_index_column, object_index_vector}); + {genjet_quantity, jet_genjet_index_column, object_jet_index_column, + object_index_vector}); } -/** +/** * @brief This function gets the jet quantity for a given object. All objects - * are usually also reconstructed as jets. This function finds the corresponding jet - * via indices that are present in nanoAODs. + * are usually also reconstructed as jets. This function finds the corresponding + * jet via indices that are present in nanoAODs. * * If the reconstruction-level jet cannot be accessed, the function returns a * default value. @@ -638,38 +641,40 @@ ROOT::RDF::RNode GetGenJetForObject(ROOT::RDF::RNode df, * @param df input dataframe * @param outputname name of the output column containing the jet quantity value * @param jet_quantity name of the column containing the jet quantity vector - * @param object_jet_index name of the column containing the association (via index) - * between the object and the jet collection - * @param object_index_vector name of the column containing the vector with the relevant - * object indices - * @param position position in the index vector that specifies which object in the - * object vector should be used to get its associated jet quantity + * @param object_jet_index name of the column containing the association (via + * index) between the object and the jet collection + * @param object_index_vector name of the column containing the vector with the + * relevant object indices + * @param position position in the index vector that specifies which object in + * the object vector should be used to get its associated jet quantity * * @return a dataframe with the new column */ template -ROOT::RDF::RNode GetJetForObject(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_quantity, - const std::string &object_jet_index, - const std::string &object_index_vector, - const int &position) { +ROOT::RDF::RNode +GetJetForObject(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &jet_quantity, + const std::string &object_jet_index, + const std::string &object_index_vector, const int &position) { // In nanoAODv12 the type ofs object to jet indices were changed to Short_t // For v9 compatibility a type casting is applied - auto [df1, object_jet_index_column] = utility::Cast, ROOT::RVec>( - df, object_jet_index+"_v12", "ROOT::VecOps::RVec", object_jet_index); - return df1.Define(outputname, + auto [df1, object_jet_index_column] = + utility::Cast, ROOT::RVec>( + df, object_jet_index + "_v12", "ROOT::VecOps::RVec", + object_jet_index); + return df1.Define( + outputname, [position](const ROOT::RVec &quantity, - const ROOT::RVec &obj_jet_idx_v12, - const ROOT::RVec &obj_indices) { + const ROOT::RVec &obj_jet_idx_v12, + const ROOT::RVec &obj_indices) { auto obj_jet_idx = static_cast>(obj_jet_idx_v12); const int obj_index = obj_indices.at(position); const int jet_index = obj_jet_idx.at(obj_index, -1); T result = quantity.at(jet_index, default_value()); - Logger::get("event::quantity::GetJetForObject")->debug( - " Retrieved jet quantity value {} for object index {}", - result, obj_index - ); + Logger::get("event::quantity::GetJetForObject") + ->debug( + " Retrieved jet quantity value {} for object index {}", + result, obj_index); return result; }, {jet_quantity, object_jet_index_column, object_index_vector}); @@ -721,7 +726,8 @@ inline ROOT::RDF::RNode Sum(ROOT::RDF::RNode df, const std::string &outputname, template inline ROOT::RDF::RNode Sum(ROOT::RDF::RNode df, const std::string &outputname, const std::string &quantity, - const std::string &index_vector, const T zero = T(0)) { + const std::string &index_vector, + const T zero = T(0)) { auto sum_per_event = [zero](const ROOT::RVec &quantity, const ROOT::RVec &indices) { Logger::get("event::quantity::Sum") @@ -734,39 +740,42 @@ inline ROOT::RDF::RNode Sum(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief This function calculates the scalar sum of an arbitrary set of quantities - * of type `float`. + * @brief This function calculates the scalar sum of an arbitrary set of + * quantities of type `float`. * - * @tparam Quantities variadic template parameter pack representing the quantity columns + * @tparam Quantities variadic template parameter pack representing the quantity + * columns * @param df input dataframe * @param outputname name of the output column containing the scalar sum - * @param quantities parameter pack of column names that contain the considered quantities + * @param quantities parameter pack of column names that contain the considered + * quantities * * @return a dataframe with a new column */ template -inline ROOT::RDF::RNode -ScalarSum(ROOT::RDF::RNode df, const std::string &outputname, - Quantities... quantities) { +inline ROOT::RDF::RNode ScalarSum(ROOT::RDF::RNode df, + const std::string &outputname, + Quantities... quantities) { auto argTuple = std::make_tuple(quantities...); std::vector QuantityList{quantities...}; const auto nQuantities = sizeof...(Quantities); using namespace ROOT::VecOps; - return df.Define( - outputname, - utility::PassAsVec([](const ROOT::RVec &quantities) { - for (const auto &quantity : quantities) { - if (quantity < 0.0) { - Logger::get("event::quantity::ScalarSum") - ->debug("Negative quantity found, returning default value!"); - return default_float; - } - } - const auto sum = Sum(quantities, float(0.0)); - return sum; - }), - QuantityList); + return df.Define(outputname, + utility::PassAsVec( + [](const ROOT::RVec &quantities) { + for (const auto &quantity : quantities) { + if (quantity < 0.0) { + Logger::get("event::quantity::ScalarSum") + ->debug("Negative quantity found, " + "returning default value!"); + return default_float; + } + } + const auto sum = Sum(quantities, float(0.0)); + return sum; + }), + QuantityList); } /** @@ -800,10 +809,11 @@ Unroll(ROOT::RDF::RNode df, const std::vector &outputnames, if (index >= outputnames.size()) { return df; } - auto df1 = df.Define( - outputnames.at(index), - [index](const std::vector &quantities) { return quantities.at(index); }, - {quantity}); + auto df1 = df.Define(outputnames.at(index), + [index](const std::vector &quantities) { + return quantities.at(index); + }, + {quantity}); return Unroll(df1, outputnames, quantity, index + 1); } @@ -834,7 +844,8 @@ inline ROOT::RDF::RNode Flag(ROOT::RDF::RNode df, const std::string &filtername, /** * @brief This function applies a filter to the input dataframe based on a - * boolean flag column. It returns only the rows where the flag value is `false`. + * boolean flag column. It returns only the rows where the flag value is + * `false`. * * @param df input dataframe * @param filtername name of the filter to be applied (used in the dataframe @@ -843,8 +854,9 @@ inline ROOT::RDF::RNode Flag(ROOT::RDF::RNode df, const std::string &filtername, * * @return a filtered dataframe */ -inline ROOT::RDF::RNode InvertedFlag(ROOT::RDF::RNode df, const std::string &filtername, - const std::string &flagname) { +inline ROOT::RDF::RNode InvertedFlag(ROOT::RDF::RNode df, + const std::string &filtername, + const std::string &flagname) { return df.Filter([](const bool flag) { return !flag; }, {flagname}, filtername); } diff --git a/include/fatjets.hxx b/include/fatjets.hxx index 7dd98b88..57202628 100644 --- a/include/fatjets.hxx +++ b/include/fatjets.hxx @@ -6,19 +6,13 @@ namespace fatjet { namespace quantity { ROOT::RDF::RNode -ParticleNet_XvsQCD(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pNet_X_decay, - const std::string &pNet_QCD, - const std::string &fatjet_collection, - const int &position); +ParticleNet_XvsQCD(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pNet_X_decay, const std::string &pNet_QCD, + const std::string &fatjet_collection, const int &position); ROOT::RDF::RNode -NsubjettinessRatio(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &tau_N, - const std::string &tau_Nm1, - const std::string &fatjet_collection, - const int &position); +NsubjettinessRatio(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &tau_N, const std::string &tau_Nm1, + const std::string &fatjet_collection, const int &position); } // end namespace quantity } // end namespace fatjet } // end namespace physicsobject diff --git a/include/genparticles.hxx b/include/genparticles.hxx index bb65d5ed..61e4204f 100644 --- a/include/genparticles.hxx +++ b/include/genparticles.hxx @@ -12,17 +12,21 @@ namespace genparticles { -ROOT::RDF::RNode GetBoson( - ROOT::RDF::RNode df, const std::string outputname, - const std::string &genparticles_pt, const std::string &genparticles_eta, - const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &genparticles_pdg_id, const std::string &genparticles_status, - const std::string &genparticles_status_flags, bool is_data); +ROOT::RDF::RNode GetBoson(ROOT::RDF::RNode df, const std::string outputname, + const std::string &genparticles_pt, + const std::string &genparticles_eta, + const std::string &genparticles_phi, + const std::string &genparticles_mass, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status, + const std::string &genparticles_status_flags, + bool is_data); ROOT::RDF::RNode GetVisibleBoson( ROOT::RDF::RNode df, const std::string outputname, const std::string &genparticles_pt, const std::string &genparticles_eta, const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &genparticles_pdg_id, const std::string &genparticles_status, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status, const std::string &genparticles_status_flags, bool is_data); namespace tau { @@ -41,22 +45,22 @@ ROOT::RDF::RNode GenMatching(ROOT::RDF::RNode df, const std::string &outputname, const std::string &genparticles_phi, const std::string &genparticles_mass, const std::string &reco_had_tau); -ROOT::RDF::RNode GenMatching( - ROOT::RDF::RNode df, const std::string &outputname, - const std::string &hadronic_gen_taus, const std::string &genparticles_pdg_id, - const std::string &genparticles_status_flags, const std::string &genparticle_motheridx, - const std::string &genparticles_pt, const std::string &genparticles_eta, - const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &reco_had_tau); +ROOT::RDF::RNode GenMatching(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &hadronic_gen_taus, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status_flags, + const std::string &genparticle_motheridx, + const std::string &genparticles_pt, + const std::string &genparticles_eta, + const std::string &genparticles_phi, + const std::string &genparticles_mass, + const std::string &reco_had_tau); } // end namespace tau -namespace drell_yan{ -ROOT::RDF::RNode DecayFlavor( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_pdg_id, - const std::string &lhe_status -); +namespace drell_yan { +ROOT::RDF::RNode DecayFlavor(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_pdg_id, + const std::string &lhe_status); } // end namespace drell_yan } // end namespace genparticles #endif /* GUARD_GENPARTICLES_H */ diff --git a/include/jets.hxx b/include/jets.hxx index 14ab619f..d5180638 100644 --- a/include/jets.hxx +++ b/include/jets.hxx @@ -1,60 +1,42 @@ #ifndef GUARD_JETS_H #define GUARD_JETS_H +#include "utility/CorrectionManager.hxx" + namespace physicsobject { namespace jet { -ROOT::RDF::RNode -RawPt(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_pt, - const std::string &jet_raw_factor); -ROOT::RDF::RNode -PtCorrectionL1(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname_L1, - const std::string &outputname_L1_T1MET, - const std::string &jet_raw_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_area, - const std::string &jet_raw_muonfactor, - const std::string &lowpt_jet_raw_pt, - const std::string &lowpt_jet_eta, - const std::string &lowpt_jet_phi, - const std::string &lowpt_jet_area, - const std::string &lowpt_jet_raw_muonfactor, - const std::string &rho, - const std::string &jec_file, - const std::string &jec_algo, - const std::string &jes_tag); -ROOT::RDF::RNode -PtCorrectionL2L3(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname_L2L3, - const std::string &outputname_L2L3_T1MET, - const std::string &jet_L1_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_area, - const std::string &jet_id, - const std::string &jet_L1_T1MET_pt, - const std::string &lowpt_jet_eta, - const std::string &lowpt_jet_phi, - const std::string &lowpt_jet_area, - const std::string &gen_jet_pt, - const std::string &gen_jet_eta, - const std::string &gen_jet_phi, - const std::string &rho, - const std::string &jer_seed, - const std::string &run, - const std::string &jec_file, - const std::string &jec_algo, - const std::string &jes_tag, - const std::vector &jes_shift_sources, - const std::string &jer_tag, - const int &jes_shift, const std::string &jer_shift, - const std::string &era); - +ROOT::RDF::RNode RawPt(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &jet_pt, + const std::string &jet_raw_factor); +ROOT::RDF::RNode PtCorrectionL1( + ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname_L1, const std::string &outputname_L1_T1MET, + const std::string &jet_raw_pt, const std::string &jet_eta, + const std::string &jet_phi, const std::string &jet_area, + const std::string &jet_raw_muonfactor, const std::string &lowpt_jet_raw_pt, + const std::string &lowpt_jet_eta, const std::string &lowpt_jet_phi, + const std::string &lowpt_jet_area, + const std::string &lowpt_jet_raw_muonfactor, const std::string &rho, + const std::string &jec_file, const std::string &jec_algo, + const std::string &jes_tag); +ROOT::RDF::RNode PtCorrectionL2L3( + ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname_L2L3, + const std::string &outputname_L2L3_T1MET, const std::string &jet_L1_pt, + const std::string &jet_eta, const std::string &jet_phi, + const std::string &jet_area, const std::string &jet_id, + const std::string &jet_L1_T1MET_pt, const std::string &lowpt_jet_eta, + const std::string &lowpt_jet_phi, const std::string &lowpt_jet_area, + const std::string &gen_jet_pt, const std::string &gen_jet_eta, + const std::string &gen_jet_phi, const std::string &rho, + const std::string &jer_seed, const std::string &run, + const std::string &jec_file, const std::string &jec_algo, + const std::string &jes_tag, + const std::vector &jes_shift_sources, + const std::string &jer_tag, const int &jes_shift, + const std::string &jer_shift, const std::string &era); ROOT::RDF::RNode PtCorrectionMC(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, @@ -65,10 +47,12 @@ PtCorrectionMC(ROOT::RDF::RNode df, const std::string &gen_jet_eta, const std::string &gen_jet_phi, const std::string &rho, const std::string &jer_seed, const std::string &jec_file, const std::string &jec_algo, - const std::string &jes_tag, const std::vector &jes_shift_sources, + const std::string &jes_tag, + const std::vector &jes_shift_sources, const std::string &jer_tag, bool reapply_jes, const int &jes_shift, const std::string &jer_shift, - const std::string &era, const bool &no_jer_for_unmatched_forward_jets = false); + const std::string &era, + const bool &no_jer_for_unmatched_forward_jets = false); ROOT::RDF::RNode PtCorrectionData(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, @@ -78,37 +62,30 @@ PtCorrectionData(ROOT::RDF::RNode df, const std::string &rho, const std::string &run, const std::string &jec_file, const std::string &jec_algo, const std::string &jes_tag, const std::string &era); -ROOT::RDF::RNode -PtCorrectionBJets(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_pt, - const std::string &scale_factor, - const std::string &bjet_mask); +ROOT::RDF::RNode PtCorrectionBJets(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &jet_pt, + const std::string &scale_factor, + const std::string &bjet_mask); ROOT::RDF::RNode CutPileupID(ROOT::RDF::RNode df, const std::string &outputname, const std::string &jet_pu_id, const std::string &jet_pt, const int &pu_id_cut, const float &pt_cut); -ROOT::RDF::RNode -VetoMap(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &jet_eta, const std::string &jet_phi, - const std::string &vetomap_file, const std::string &vetomap_name, - const std::string &vetomap_type); +ROOT::RDF::RNode VetoMap(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &jet_eta, const std::string &jet_phi, + const std::string &vetomap_file, + const std::string &vetomap_name, + const std::string &vetomap_type); ROOT::RDF::RNode VetoMap(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &jet_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_id, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_vetomap_file, - const std::string &jet_vetomap_name, - const std::string &jet_vetomap_type, - const float &min_pt, - const int &id_wp, - const float &max_em_frac); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &jet_pt, + const std::string &jet_eta, const std::string &jet_phi, + const std::string &jet_id, const std::string &jet_ch_em_ef, + const std::string &jet_ne_em_ef, const std::string &jet_vetomap_file, + const std::string &jet_vetomap_name, + const std::string &jet_vetomap_type, const float &min_pt, + const int &id_wp, const float &max_em_frac); ROOT::RDF::RNode VetoOverlappingJets(ROOT::RDF::RNode df, const std::string &outputname, const std::string &jet_eta, const std::string &jet_phi, @@ -128,52 +105,42 @@ ROOT::RDF::RNode VetoOverlappingJetsWithIsoLepton(ROOT::RDF::RNode df, namespace quantity { ROOT::RDF::RNode -PatchedIDNanoV12( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_pt, - const std::string &jet_eta, - const std::string &jet_id, - const std::string &jet_ne_h_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_mu_ef, - const std::string &jet_ch_em_ef); -ROOT::RDF::RNode +PatchedIDNanoV12(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &jet_pt, const std::string &jet_eta, + const std::string &jet_id, const std::string &jet_ne_h_ef, + const std::string &jet_ne_em_ef, const std::string &jet_mu_ef, + const std::string &jet_ch_em_ef); +ROOT::RDF::RNode ID(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &jet_eta, - const std::string &jet_ch_h_ef, - const std::string &jet_ne_h_ef, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_mu_ef, - const std::string &jet_ch_mult, - const std::string &jet_ne_mult, - const std::string &jet_id_file, - const std::string &jet_name); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &jet_eta, + const std::string &jet_ch_h_ef, const std::string &jet_ne_h_ef, + const std::string &jet_ch_em_ef, const std::string &jet_ne_em_ef, + const std::string &jet_mu_ef, const std::string &jet_ch_mult, + const std::string &jet_ne_mult, const std::string &jet_id_file, + const std::string &jet_name); } // end namespace quantity namespace scalefactor { ROOT::RDF::RNode BtaggingShape(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &btag_value, - const std::string &flavor, const std::string &jet_mask, - const std::string &bjet_mask, const std::string &jet_veto_mask, - const std::string &sf_file, const std::string &sf_name, - const std::string &variation); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &btag_value, + const std::string &flavor, const std::string &jet_mask, + const std::string &bjet_mask, const std::string &jet_veto_mask, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation); ROOT::RDF::RNode BtaggingWP(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &flavor, - const std::string &jet_mask, const std::string &bjet_mask, - const std::string &jet_veto_mask, const std::string &sf_file, - const std::string &sf_name, const std::string &variation, - const std::string &btag_wp); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &flavor, + const std::string &jet_mask, const std::string &bjet_mask, + const std::string &jet_veto_mask, const std::string &sf_file, + const std::string &sf_name, const std::string &variation, + const std::string &btag_wp); } // end namespace scalefactor } // end namespace jet } // end namespace physicsobject diff --git a/include/lorentzvectors.hxx b/include/lorentzvectors.hxx index 1e68d16c..46e50639 100644 --- a/include/lorentzvectors.hxx +++ b/include/lorentzvectors.hxx @@ -4,21 +4,22 @@ #include "ROOT/RDFHelpers.hxx" #include "ROOT/RDataFrame.hxx" #include "ROOT/RVec.hxx" -#include "utility/utility.hxx" #include "defaults.hxx" +#include "utility/utility.hxx" #include namespace lorentzvector { /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors. If one of the Lorentz vectors is not well defined (has + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors. If one of the Lorentz vectors is not well defined (has * default values), the function returns a default Lorentz vector. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the summed Lorentz vector + * @param outputname name of the output column containing the summed Lorentz + * vector * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` * @@ -26,7 +27,7 @@ namespace lorentzvector { */ template ROOT::RDF::RNode Sum(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -45,55 +46,43 @@ ROOT::RDF::RNode Sum(ROOT::RDF::RNode df, const std::string &outputname, }), LV_list); } -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, - const std::string &index_vector, - const int position); -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass, + const std::string &index_vector, const int position); +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass, const int index); -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass); +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass); ROOT::RDF::RNode BuildMET(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &met_pt, const std::string &met_phi); + const std::string &met_pt, + const std::string &met_phi); ROOT::RDF::RNode BuildCollection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, - const std::string &object_mask); + const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, + const std::string &mass, + const std::string &object_mask); ROOT::RDF::RNode BuildCollection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass); + const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, + const std::string &mass); ROOT::RDF::RNode Scale(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector, - const float &scalefactor); + const std::string &vector, const float &scalefactor); /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors (can also be only one) and returns its transverse momentum - * (\f$p_T\f$). If one of the Lorentz vectors is not well defined (has default + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors (can also be only one) and returns its transverse momentum + * (\f$p_T\f$). If one of the Lorentz vectors is not well defined (has default * values), the function returns a default value. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the \f$p_T\f$ of the + * @param outputname name of the output column containing the \f$p_T\f$ of the * summed Lorentz vectors * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` @@ -102,7 +91,7 @@ ROOT::RDF::RNode Scale(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetPt(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -117,22 +106,23 @@ ROOT::RDF::RNode GetPt(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.pt(); }), LV_list); } /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors (can also be only one) and returns its pseudorapodity - * \f$\eta\f$. If one of the Lorentz vectors is not well defined (has default + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors (can also be only one) and returns its pseudorapodity + * \f$\eta\f$. If one of the Lorentz vectors is not well defined (has default * values), the function returns a default value. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the pseudorapidity + * @param outputname name of the output column containing the pseudorapidity * \f$\eta\f$ of the summed Lorentz vectors * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` @@ -141,7 +131,7 @@ ROOT::RDF::RNode GetPt(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetEta(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -156,22 +146,23 @@ ROOT::RDF::RNode GetEta(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.eta(); }), LV_list); } /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors (can also be only one) and returns its azimuthal angle - * \f$\phi\f$. If one of the Lorentz vectors is not well defined (has default + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors (can also be only one) and returns its azimuthal angle + * \f$\phi\f$. If one of the Lorentz vectors is not well defined (has default * values), the function returns a default value. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the azimuthal angle + * @param outputname name of the output column containing the azimuthal angle * \f$\phi\f$ of the summed Lorentz vectors * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` @@ -180,7 +171,7 @@ ROOT::RDF::RNode GetEta(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetPhi(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -195,22 +186,23 @@ ROOT::RDF::RNode GetPhi(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.phi(); }), LV_list); } /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors (can also be only one) and returns its invariant mass. If - * one of the Lorentz vectors is not well defined (has default values), the + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors (can also be only one) and returns its invariant mass. If + * one of the Lorentz vectors is not well defined (has default values), the * function returns a default value. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the invariant mass + * @param outputname name of the output column containing the invariant mass * of the summed Lorentz vectors * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` @@ -219,7 +211,7 @@ ROOT::RDF::RNode GetPhi(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetMass(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -234,22 +226,23 @@ ROOT::RDF::RNode GetMass(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.mass(); }), LV_list); } /** - * @brief This function constructs a vectorial sum of an arbitrary number of - * Lorentz vectors (can also be only one) and returns its energy. If one of - * the Lorentz vectors is not well defined (has default values), the function + * @brief This function constructs a vectorial sum of an arbitrary number of + * Lorentz vectors (can also be only one) and returns its energy. If one of + * the Lorentz vectors is not well defined (has default values), the function * returns a default value. * - * @tparam Lorentzvectors variadic template parameter pack representing the + * @tparam Lorentzvectors variadic template parameter pack representing the * Lorentz vector columns * @param df input dataframe - * @param outputname name of the output column containing the energy of the + * @param outputname name of the output column containing the energy of the * summed Lorentz vectors * @param LVs Parameter pack of column names that contain the considered * Lorentz vectors, must be of type `ROOT::Math::PtEtaPhiMVector` @@ -258,7 +251,7 @@ ROOT::RDF::RNode GetMass(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetEnergy(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -273,7 +266,8 @@ ROOT::RDF::RNode GetEnergy(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.energy(); }), LV_list); @@ -297,7 +291,7 @@ ROOT::RDF::RNode GetEnergy(ROOT::RDF::RNode df, const std::string &outputname, */ template ROOT::RDF::RNode GetRapidity(ROOT::RDF::RNode df, const std::string &outputname, - const Lorentzvectors &...LVs) { + const Lorentzvectors &...LVs) { std::vector LV_list; utility::appendParameterPackToVector(LV_list, LVs...); const auto n_LVs = sizeof...(Lorentzvectors); @@ -312,7 +306,8 @@ ROOT::RDF::RNode GetRapidity(ROOT::RDF::RNode df, const std::string &outputname, return default_float; } } - ROOT::Math::PtEtaPhiMVector new_LV = Sum(LVs, ROOT::Math::PtEtaPhiMVector()); + ROOT::Math::PtEtaPhiMVector new_LV = + Sum(LVs, ROOT::Math::PtEtaPhiMVector()); return (float)new_LV.Rapidity(); }), LV_list); diff --git a/include/met.hxx b/include/met.hxx index b5945281..bade4e3a 100644 --- a/include/met.hxx +++ b/include/met.hxx @@ -1,47 +1,52 @@ #ifndef GUARD_MET_H #define GUARD_MET_H -#include "../include/utility/utility.hxx" -#include "../include/event.hxx" +#include "event.hxx" +#include "utility/CorrectionManager.hxx" +#include "utility/utility.hxx" namespace met { /** - * @brief Calculates the hadronic recoil and its components parallel and perpendicular - * to a visible system's momentum. The recoil is a crucial observable in analyses with - * invisible particles (like neutrinos). + * @brief Calculates the hadronic recoil and its components parallel and + * perpendicular to a visible system's momentum. The recoil is a crucial + * observable in analyses with invisible particles (like neutrinos). * - * The hadronic recoil (\f$\vec{u}_T\f$) is defined as the vector sum of the transverse - * momenta of all hadronic particles in the event. By momentum conservation in the - * transverse plane, it must balance the momentum of the hard-scatter system (visible - * leptons/photons and invisible MET). + * The hadronic recoil (\f$\vec{u}_T\f$) is defined as the vector sum of the + * transverse momenta of all hadronic particles in the event. By momentum + * conservation in the transverse plane, it must balance the momentum of the + * hard-scatter system (visible leptons/photons and invisible MET). * * It is calculated as: * \f[ * \vec{u}_T = -(\vec{p}_T^{\text{visible}} + \vec{p}_T^{\text{miss}}) * \f] - * where \f$\vec{p}_T^{\text{visible}}\f$ is the vector sum of the transverse momenta - * of the specified input Lorentz vectors (e.g., \f$\vec{p}_{T, \ell\ell}\f$ for a - * Z boson event). The function then projects this recoil vector onto the axis defined - * by the direction of the visible system's transverse momentum, - * \f$\hat{q}_T = \frac{\vec{p}_T^{\text{visible}}}{|\vec{p}_T^{\text{visible}}|}\f$. + * where \f$\vec{p}_T^{\text{visible}}\f$ is the vector sum of the transverse + * momenta of the specified input Lorentz vectors (e.g., \f$\vec{p}_{T, + * \ell\ell}\f$ for a Z boson event). The function then projects this recoil + * vector onto the axis defined by the direction of the visible system's + * transverse momentum, + * \f$\hat{q}_T = + * \frac{\vec{p}_T^{\text{visible}}}{|\vec{p}_T^{\text{visible}}|}\f$. * - * - **Parallel Component (\f$u_\parallel\f$)**: The projection of the recoil onto the - * visible system's axis. It is a measure of the recoil's response. + * - **Parallel Component (\f$u_\parallel\f$)**: The projection of the recoil + * onto the visible system's axis. It is a measure of the recoil's response. * \f[ u_\parallel = \vec{u}_T \cdot \hat{q}_T \f] - * - **Perpendicular Component (\f$u_\perp\f$)**: The component of the recoil orthogonal - * to the visible system's axis. It is a measure of the recoil's resolution. + * - **Perpendicular Component (\f$u_\perp\f$)**: The component of the recoil + * orthogonal to the visible system's axis. It is a measure of the recoil's + * resolution. * \f[ u_\perp = |\vec{u}_T \times \hat{q}_T| \f] (calculated with a sign). * * The function returns a vector of two doubles: `{u_parallel, u_perp}`. * - * @tparam Lorentzvectors variadic template parameter pack representing Lorentz vectors + * @tparam Lorentzvectors variadic template parameter pack representing Lorentz + * vectors * @param df input dataframe - * @param outputname name of the new column containing a `std::vector` with the - * parallel and perpendicular recoil components + * @param outputname name of the new column containing a `std::vector` + * with the parallel and perpendicular recoil components * @param p4_met name of the column containing the MET Lorentz vector - * @param lorentzvectors parameter pack of column names containing Lorentz vectors of - * visible particles (e.g., "Lepton_p4_1", "Lepton_p4_2"). + * @param lorentzvectors parameter pack of column names containing Lorentz + * vectors of visible particles (e.g., "Lepton_p4_1", "Lepton_p4_2"). * * @return a dataframe with the new column containing parallel and perpendicular * recoil components @@ -49,10 +54,9 @@ namespace met { * @warning Implemented calculation was not cross checked. */ template -ROOT::RDF::RNode GetHadronicRecoil(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &p4_met, - Lorentzvectors... lorentzvectors) { +ROOT::RDF::RNode +GetHadronicRecoil(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, Lorentzvectors... lorentzvectors) { auto argTuple = std::make_tuple(lorentzvectors...); std::vector LorentzvectorList{lorentzvectors...}; const auto nLVs = sizeof...(Lorentzvectors); @@ -60,89 +64,77 @@ ROOT::RDF::RNode GetHadronicRecoil(ROOT::RDF::RNode df, using namespace ROOT::VecOps; auto calc_recoil = [](const ROOT::Math::PtEtaPhiMVector &p4_met, const ROOT::RVec &LVs) { - // Calculate the multilepton vector - ROOT::Math::PtEtaPhiMVector vis_recoil_vector; - for (const auto &vector : LVs) { - vis_recoil_vector += vector; - } - double met = p4_met.Et(); - double met_phi = p4_met.Phi(); + // Calculate the multilepton vector + ROOT::Math::PtEtaPhiMVector vis_recoil_vector; + for (const auto &vector : LVs) { + vis_recoil_vector += vector; + } + double met = p4_met.Et(); + double met_phi = p4_met.Phi(); - double pUX = -met * cos(met_phi) - - vis_recoil_vector.Pt() * cos(vis_recoil_vector.Phi()); - double pUY = -met * sin(met_phi) - - vis_recoil_vector.Pt() * sin(vis_recoil_vector.Phi()); - double pU = sqrt(pUX * pUX + pUY * pUY); - double pCos = (pUX * cos(vis_recoil_vector.Phi()) + - pUY * sin(vis_recoil_vector.Phi())) / - pU; - double pSin = -(pUX * sin(vis_recoil_vector.Phi()) - - pUY * cos(vis_recoil_vector.Phi())) / - pU; - // Return the vector of parallel and perpendicular components - return std::vector{pU * pCos, pU * pSin}; - }; - return df.Define(outputname, - utility::PassAsVec(calc_recoil), - {p4_met, LorentzvectorList}); + double pUX = -met * cos(met_phi) - + vis_recoil_vector.Pt() * cos(vis_recoil_vector.Phi()); + double pUY = -met * sin(met_phi) - + vis_recoil_vector.Pt() * sin(vis_recoil_vector.Phi()); + double pU = sqrt(pUX * pUX + pUY * pUY); + double pCos = (pUX * cos(vis_recoil_vector.Phi()) + + pUY * sin(vis_recoil_vector.Phi())) / + pU; + double pSin = -(pUX * sin(vis_recoil_vector.Phi()) - + pUY * cos(vis_recoil_vector.Phi())) / + pU; + // Return the vector of parallel and perpendicular components + return std::vector{pU * pCos, pU * pSin}; + }; + return df.Define( + outputname, + utility::PassAsVec(calc_recoil), + {p4_met, LorentzvectorList}); }; -ROOT::RDF::RNode RecoilCorrection( - ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &p4_met, const std::string &p4_gen_boson, - const std::string &p4_vis_gen_boson, const std::string &n_jets, - const std::string &corr_file, const std::string &corr_name, - const std::string &method, const std::string &order, - const std::string &variation, const bool apply_correction); -ROOT::RDF::RNode RecoilCorrection( - ROOT::RDF::RNode df, const std::string &outputname, - const std::string &p4_met, const std::string &p4_gen_boson, - const std::string &p4_vis_gen_boson, const std::string &jet_pt, - const std::string &corr_file, const std::string &syst_file, - const bool apply_correction, const bool resolution, const bool response, - const bool shift_up, const bool shift_down, const bool is_Wjets); -ROOT::RDF::RNode METPhiCorrection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &p4_met, - const std::string &n_pv, - const std::string &run, - const std::string &corr_file, - const std::string &corr_name); -ROOT::RDF::RNode METPhiCorrection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &p4_met, - const std::string &n_pv, - const std::string &corr_file, - const std::string &corr_name, - const std::string &met_type, - const std::string &era, - const bool is_mc, - const std::string &stat_variation, - const std::string &pileup_variation); - ROOT::RDF::RNode -Type1Correction(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &raw_met, - const std::string &jet_pt_l1corr, - const std::string &jet_pt_corr, - const std::string &jet_phi, - const std::string &jet_muon_subtr_delta_phi, - const std::string &jet_chEmEF, - const std::string &jet_neEmEF, - const std::string &low_pt_jet_phi, - const std::string &low_pt_jet_muon_subtr_delta_phi, - const std::string &low_pt_jet_EmEF); +RecoilCorrection(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &p4_met, + const std::string &p4_gen_boson, + const std::string &p4_vis_gen_boson, const std::string &n_jets, + const std::string &corr_file, const std::string &corr_name, + const std::string &method, const std::string &order, + const std::string &variation, const bool apply_correction); +ROOT::RDF::RNode +RecoilCorrection(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &p4_gen_boson, + const std::string &p4_vis_gen_boson, const std::string &jet_pt, + const std::string &corr_file, const std::string &syst_file, + const bool apply_correction, const bool resolution, + const bool response, const bool shift_up, + const bool shift_down, const bool is_Wjets); +ROOT::RDF::RNode +METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &n_pv, + const std::string &run, const std::string &corr_file, + const std::string &corr_name); +ROOT::RDF::RNode +METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &n_pv, + const std::string &corr_file, const std::string &corr_name, + const std::string &met_type, const std::string &era, + const bool is_mc, const std::string &stat_variation, + const std::string &pileup_variation); +ROOT::RDF::RNode +Type1Correction(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &raw_met, const std::string &jet_pt_l1corr, + const std::string &jet_pt_corr, const std::string &jet_phi, + const std::string &jet_muon_subtr_delta_phi, + const std::string &jet_chEmEF, const std::string &jet_neEmEF, + const std::string &low_pt_jet_phi, + const std::string &low_pt_jet_muon_subtr_delta_phi, + const std::string &low_pt_jet_EmEF); ROOT::RDF::RNode -Type1Correction(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &raw_met, - const std::string &jet_pt_l1corr, - const std::string &jet_pt_corr, - const std::string &jet_phi, - const std::string &jet_chEmEF, - const std::string &jet_neEmEF, - const std::string &low_pt_jet_phi); +Type1Correction(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &raw_met, const std::string &jet_pt_l1corr, + const std::string &jet_pt_corr, const std::string &jet_phi, + const std::string &jet_chEmEF, const std::string &jet_neEmEF, + const std::string &low_pt_jet_phi); } // end namespace met @@ -160,7 +152,8 @@ namespace lorentzvector { * - p_{x,\text{object}}^{\text{corrected}} \\ * E_{T,miss,y}^{\text{corrected}} = E_{T,miss,y} + p_{y,\text{object}} * - p_{y,\text{object}}^{\text{corrected}} \\ - * E_{T,miss}^{\text{corrected}} = \sqrt{E_{T,miss,x}^{\text{corrected}} * E_{T,miss,x}^{\text{corrected}} + * E_{T,miss}^{\text{corrected}} = \sqrt{E_{T,miss,x}^{\text{corrected}} * + * E_{T,miss,x}^{\text{corrected}} * + E_{T,miss,y}^{\text{corrected}} * E_{T,miss,y}^{\text{corrected}}} * \f] * @@ -180,9 +173,8 @@ namespace lorentzvector { */ template ROOT::RDF::RNode PropagateToMET(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &p4_met, - Args... args) { + const std::string &outputname, + const std::string &p4_met, Args... args) { using namespace ROOT::VecOps; auto argTuple = std::make_tuple(args...); auto apply_propagation = utility::extractLastArgument(argTuple); @@ -192,7 +184,8 @@ ROOT::RDF::RNode PropagateToMET(ROOT::RDF::RNode df, const auto n_LVs = sizeof...(Args); const auto n_Objects = (n_LVs - 1) / 2; static_assert((n_Objects > 0) && (n_Objects % 2) == 0, - "Provide an even, non-zero number of object columns: first half uncorrected, second half corrected."); + "Provide an even, non-zero number of object columns: first " + "half uncorrected, second half corrected."); if (apply_propagation) { // correct for the objects, store the MET in an intermediate column @@ -201,29 +194,40 @@ ROOT::RDF::RNode PropagateToMET(ROOT::RDF::RNode df, return df.Define( outputname, utility::PassAsVec( - [n_Objects](const ROOT::RVec &LVs) { + [n_Objects]( + const ROOT::RVec &LVs) { const ROOT::Math::PtEtaPhiMVector &met = LVs.at(n_Objects * 2); ROOT::Math::PtEtaPhiMVector corrected_met = met; - // We propagate the object corrections to the MET by scaling the x - // and y component of the MET according to the correction of the objects + // We propagate the object corrections to the MET by scaling + // the x and y component of the MET according to the + // correction of the objects for (auto i = 0; i < n_Objects; ++i) { - float corr_x = LVs.at(i).Px() - LVs.at(n_Objects + i).Px(); - float corr_y = LVs.at(i).Py() - LVs.at(n_Objects + i).Py(); + float corr_x = + LVs.at(i).Px() - LVs.at(n_Objects + i).Px(); + float corr_y = + LVs.at(i).Py() - LVs.at(n_Objects + i).Py(); float MetX = corrected_met.Px() + corr_x; float MetY = corrected_met.Py() + corr_y; - Logger::get("lorentzvector::PropagateToMET")->debug("corr_x {}", corr_x); - Logger::get("lorentzvector::PropagateToMET")->debug("corr_y {}", corr_y); - Logger::get("lorentzvector::PropagateToMET")->debug("MetX {}", MetX); - Logger::get("lorentzvector::PropagateToMET")->debug("MetY {}", MetY); + Logger::get("lorentzvector::PropagateToMET") + ->debug("corr_x {}", corr_x); + Logger::get("lorentzvector::PropagateToMET") + ->debug("corr_y {}", corr_y); + Logger::get("lorentzvector::PropagateToMET") + ->debug("MetX {}", MetX); + Logger::get("lorentzvector::PropagateToMET") + ->debug("MetY {}", MetY); - corrected_met.SetPxPyPzE(MetX, MetY, 0, - std::sqrt(MetX * MetX + MetY * MetY)); + corrected_met.SetPxPyPzE( + MetX, MetY, 0, + std::sqrt(MetX * MetX + MetY * MetY)); Logger::get("lorentzvector::PropagateToMET") - ->debug("corrected_object pt - {}", LVs.at(n_Objects + i).Pt()); + ->debug("corrected_object pt - {}", + LVs.at(n_Objects + i).Pt()); Logger::get("lorentzvector::PropagateToMET") - ->debug("uncorrected_object pt - {}", LVs.at(i).Pt()); + ->debug("uncorrected_object pt - {}", + LVs.at(i).Pt()); Logger::get("lorentzvector::PropagateToMET") ->debug("initial MET {}", met.Pt()); Logger::get("lorentzvector::PropagateToMET") @@ -235,19 +239,21 @@ ROOT::RDF::RNode PropagateToMET(ROOT::RDF::RNode df, } else { // if we do not apply the propagation, just rename the met column to // the new outputname and dont change anything else - return event::quantity::Rename(df, outputname, p4_met); + return event::quantity::Rename( + df, outputname, p4_met); } } } // end namespace lorentzvector namespace physicsobject { -ROOT::RDF::RNode PropagateToMET( - ROOT::RDF::RNode df, const std::string &outputname, const std::string &p4_met, - const std::string &pt_corrected, const std::string &eta_corrected, - const std::string &phi_corrected, const std::string &mass_corrected, - const std::string &pt, const std::string &eta, - const std::string &phi, const std::string &mass, - bool apply_propagation, float min_pt); +ROOT::RDF::RNode +PropagateToMET(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &pt_corrected, + const std::string &eta_corrected, + const std::string &phi_corrected, + const std::string &mass_corrected, const std::string &pt, + const std::string &eta, const std::string &phi, + const std::string &mass, bool apply_propagation, float min_pt); } // end namespace physicsobject #endif /* GUARD_MET_H */ diff --git a/include/ml.hxx b/include/ml.hxx index 5c9aa559..04bf554b 100644 --- a/include/ml.hxx +++ b/include/ml.hxx @@ -1,10 +1,9 @@ #ifndef GUARD_ML_H #define GUARD_ML_H -#include "../include/utility/CorrectionManager.hxx" -#include "../include/utility/OnnxSessionManager.hxx" #include "TMVA/RModel.hxx" -#include "TMVA/RModelParser_ONNX.hxx" +#include "utility/CorrectionManager.hxx" +#include "utility/OnnxSessionManager.hxx" #include "utility/utility.hxx" #include @@ -102,4 +101,4 @@ inline ROOT::RDF::RNode GenericOnnxEvaluator( return df1; } } // end namespace ml -#endif /* GUARD_ML_H */ \ No newline at end of file +#endif /* GUARD_ML_H */ diff --git a/include/muons.hxx b/include/muons.hxx index 6a2acc06..835f6df4 100644 --- a/include/muons.hxx +++ b/include/muons.hxx @@ -1,6 +1,8 @@ #ifndef GUARD_MUONS_H #define GUARD_MUONS_H +#include "utility/CorrectionManager.hxx" + namespace physicsobject { namespace muon { diff --git a/include/pairselection.hxx b/include/pairselection.hxx index aa15d62d..fc88791e 100644 --- a/include/pairselection.hxx +++ b/include/pairselection.hxx @@ -20,19 +20,17 @@ bool check_mother(ROOT::RVec genparticles, const int index, const int mother_pdgid); namespace ditau_pairselection { -ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, +ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, const std::string &outputname, const std::string &recopair, const std::string &genindex_particle1, const std::string &genindex_particle2); ROOT::RDF::RNode -buildtruegenpair(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &statusflags, - const std::string &status, const std::string &pdgids, - const std::string &motherids, const std::string &pts, - const int mother_pdgid, - const int daughter_1_pdgid, const int daughter_2_pdgid); +buildtruegenpair(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &statusflags, const std::string &status, + const std::string &pdgids, const std::string &motherids, + const std::string &pts, const int mother_pdgid, + const int daughter_1_pdgid, const int daughter_2_pdgid); ROOT::RDF::RNode flagGoodPairs(ROOT::RDF::RNode df, const std::string &flagname, const std::string &pairname); auto compareForPairs(const ROOT::RVec &lep1pt, diff --git a/include/physicsobjects.hxx b/include/physicsobjects.hxx index a0906fc0..99926732 100644 --- a/include/physicsobjects.hxx +++ b/include/physicsobjects.hxx @@ -5,36 +5,11 @@ namespace physicsobject { -// /** -// * @brief Truncates an input vector to match the size of a reference vector. -// * -// * @tparam T type of the input vector elements -// * @param df input dataframe -// * @param outputname name of the output column -// * @param input_vector name of the input vector column -// * @param reference_vector name of the reference vector column -// * @return a dataframe with a new column containing the truncated input vector -// */ -// template -// inline ROOT::RDF::RNode TruncateToSize(ROOT::RDF::RNode df, -// const std::string &outputname, -// const std::string &input_vector, -// const std::string &reference_vector) { -// return df.Define(outputname, -// [](const ROOT::RVec &input, const ROOT::RVec &reference) { -// ROOT::RVec result; -// for (std::size_t i = 0; i < reference.size(); ++i) { -// result.push_back(input.at(i)); -// } -// return result; -// }, {input_vector, reference_vector}); -// } - /** * @brief This function takes multiple masks and applies a logical operation - * (`"any_of"`, `"all_of"`, or `"none_of"`) elemet-wise to generate a combined mask. - * The function ensures that elements are correctly merged based on the given - * mode: + * (`"any_of"`, `"all_of"`, or `"none_of"`) elemet-wise to generate a combined + * mask. The function ensures that elements are correctly merged based on the + * given mode: * * - `"any_of"`: The resulting mask contains true values if any element of * the input masks is true (element-wise) @@ -340,7 +315,7 @@ CutQuantity(ROOT::RDF::RNode df, const std::string &outputname, */ template inline ROOT::RDF::RNode Size(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_quantity) { + const std::string &vector_quantity) { return df.Define(outputname, [](const ROOT::RVec &quantity) { int length = quantity.size(); diff --git a/include/quantities.hxx b/include/quantities.hxx index 488eeb3d..856ea498 100644 --- a/include/quantities.hxx +++ b/include/quantities.hxx @@ -7,11 +7,14 @@ namespace quantities { ROOT::RDF::RNode DeltaPhi(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2); + const std::string &vector_1, + const std::string &vector_2); ROOT::RDF::RNode DeltaEta(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2); + const std::string &vector_1, + const std::string &vector_2); ROOT::RDF::RNode DeltaR(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2); + const std::string &vector_1, + const std::string &vector_2); ROOT::RDF::RNode PairHemisphere(ROOT::RDF::RNode df, const std::string &outputname, const std::string &vector_1, @@ -21,24 +24,30 @@ ROOT::RDF::RNode PzetaMissVis(ROOT::RDF::RNode df, const std::string &vector_1, const std::string &vector_2, const std::string &vector_3); -ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2); -ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2, - const std::string &vector_3); -ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2, - const std::string &vector_3); +ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2); +ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2, + const std::string &vector_3); +ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2, + const std::string &vector_3); ROOT::RDF::RNode FastMtt(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &pt_1, const std::string &pt_2, - const std::string &eta_1, const std::string &eta_2, - const std::string &phi_1, const std::string &phi_2, - const std::string &mass_1, const std::string &mass_2, - const std::string &met_pt, const std::string &met_phi, - const std::string &met_cov_xx, const std::string &met_cov_xy, - const std::string &met_cov_yy, const std::string &decay_mode_1, - const std::string &decay_mode_2, const std::string &finalstate); + const std::string &pt_1, const std::string &pt_2, + const std::string &eta_1, const std::string &eta_2, + const std::string &phi_1, const std::string &phi_2, + const std::string &mass_1, const std::string &mass_2, + const std::string &met_pt, const std::string &met_phi, + const std::string &met_cov_xx, const std::string &met_cov_xy, + const std::string &met_cov_yy, const std::string &decay_mode_1, + const std::string &decay_mode_2, const std::string &finalstate); ROOT::RDF::RNode deltaPhi_WH(ROOT::RDF::RNode df, const std::string &outputname, const std::string &vector_1, const std::string &vector_2, diff --git a/include/reweighting.hxx b/include/reweighting.hxx index ec3f4290..46e0b9c2 100644 --- a/include/reweighting.hxx +++ b/include/reweighting.hxx @@ -1,50 +1,45 @@ #ifndef GUARD_REWEIGHTING_H #define GUARD_REWEIGHTING_H +#include "utility/CorrectionManager.hxx" + namespace event { namespace reweighting { ROOT::RDF::RNode Pileup(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &true_pileup_number, - const std::string &corr_file, const std::string &corr_name, - const std::string &variation); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &true_pileup_number, + const std::string &corr_file, const std::string &corr_name, + const std::string &variation); ROOT::RDF::RNode PartonShower(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &ps_weights, - const float isr, const float fsr); -ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_scale_weights, - const float mu_r, const float mu_f); -ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_pdf_weights, - const std::string &variation); -ROOT::RDF::RNode LHEalphaS(ROOT::RDF::RNode df, - const std::string &outputname, + const std::string &outputname, + const std::string &ps_weights, const float isr, + const float fsr); +ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_scale_weights, + const float mu_r, const float mu_f); +ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, const std::string &outputname, const std::string &lhe_pdf_weights, const std::string &variation); -ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &genparticles_pdg_id, - const std::string &genparticles_status_flags, - const std::string &genparticles_pt); -ROOT::RDF::RNode ZBosonPt(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &gen_boson, - const std::string &corr_file, - const std::string &corr_name, - const std::string &order, - const std::string &variation); -ROOT::RDF::RNode ZPtMass(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &gen_boson, - const std::string &workspace_file, - const std::string &functor_name, - const std::string &argset); +ROOT::RDF::RNode LHEalphaS(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_pdf_weights, + const std::string &variation); +ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status_flags, + const std::string &genparticles_pt); +ROOT::RDF::RNode +ZBosonPt(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &gen_boson, + const std::string &corr_file, const std::string &corr_name, + const std::string &order, const std::string &variation); +ROOT::RDF::RNode ZPtMass(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &gen_boson, + const std::string &workspace_file, + const std::string &functor_name, + const std::string &argset); } // end namespace reweighting } // end namespace event #endif /* GUARD_REWEIGHTING_H */ diff --git a/include/taus.hxx b/include/taus.hxx index c687707e..f7c37475 100644 --- a/include/taus.hxx +++ b/include/taus.hxx @@ -1,32 +1,29 @@ #ifndef GUARD_TAUS_H #define GUARD_TAUS_H +#include "utility/CorrectionManager.hxx" + namespace physicsobject { namespace tau { -std::string get_tes_variation( - const float &abs_eta, - const int &decay_mode, - const int &gen_match, - const std::string &variation_efake_dm0_barrel, - const std::string &variation_efake_dm1_barrel, - const std::string &variation_efake_dm0_endcap, - const std::string &variation_efake_dm1_endcap, - const std::string &variation_mufake, - const std::string &variation_gentau_dm0, - const std::string &variation_gentau_dm1, - const std::string &variation_gentau_dm10, - const std::string &variation_gentau_dm11 -); -ROOT::RDF::RNode -PtCorrectionMC( +std::string get_tes_variation(const float &abs_eta, const int &decay_mode, + const int &gen_match, + const std::string &variation_efake_dm0_barrel, + const std::string &variation_efake_dm1_barrel, + const std::string &variation_efake_dm0_endcap, + const std::string &variation_efake_dm1_endcap, + const std::string &variation_mufake, + const std::string &variation_gentau_dm0, + const std::string &variation_gentau_dm1, + const std::string &variation_gentau_dm10, + const std::string &variation_gentau_dm11); +ROOT::RDF::RNode PtCorrectionMC( ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, const std::string &outputname, const std::string &pt, const std::string &eta, const std::string &decay_mode, const std::string &gen_match, const std::string &es_file, - const std::string &correction_name, - const std::string &id_algorithm, + const std::string &correction_name, const std::string &id_algorithm, const std::string &variation_efake_dm0_barrel, const std::string &variation_efake_dm1_barrel, const std::string &variation_efake_dm0_endcap, @@ -36,9 +33,7 @@ PtCorrectionMC( const std::string &variation_gentau_dm1, const std::string &variation_gentau_dm10, const std::string &variation_gentau_dm11, - const std::string &id_vs_jet_wp = "", - const std::string &id_vs_ele_wp = "" -); + const std::string &id_vs_jet_wp = "", const std::string &id_vs_ele_wp = ""); ROOT::RDF::RNode PtCorrectionMC_eleFake(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, @@ -76,10 +71,14 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &eta, const std::string &decay_mode, const std::string &gen_match, const std::string &es_file, const std::string &correction_name, const std::string &id_algorithm, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf); + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf); ROOT::RDF::RNode PtCorrectionMC_genuineTau( ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, @@ -99,18 +98,24 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &gen_match, const std::string &es_file, const std::string &correction_name, const std::string &id_algorithm, const std::string &wp, const std::string &vsele_wp, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf); + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf); namespace quantity { ROOT::RDF::RNode IDFlag_v9(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &ID, const std::string &index_vector, - const int &position, const int &wp); + const std::string &ID, + const std::string &index_vector, const int &position, + const int &wp); ROOT::RDF::RNode IDFlag_v12(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &ID, const std::string &index_vector, - const int &position, const int &wp); + const std::string &ID, + const std::string &index_vector, + const int &position, const int &wp); } // end namespace quantity namespace scalefactor { @@ -118,92 +123,75 @@ namespace scalefactor { ROOT::RDF::RNode Id_vsJet_lt(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::vector &selected_dms, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::vector &selected_dms, const std::string &wp, + const std::string &vsele_wp, const std::string &sf_dependence, const std::string &sf_vsjet_tau30to35, const std::string &sf_vsjet_tau35to40, const std::string &sf_vsjet_tau40to500, const std::string &sf_vsjet_tau500to1000, const std::string &sf_vsjet_tau1000toinf); -ROOT::RDF::RNode Id_vsJet( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, const std::string &sf_name, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, - const std::string &variation_dm0, - const std::string &variation_dm1, - const std::string &variation_dm10, - const std::string &variation_dm11); -ROOT::RDF::RNode Id_vsJet( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, const std::string &sf_name, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf); -ROOT::RDF::RNode +ROOT::RDF::RNode +Id_vsJet(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::string &wp, const std::string &vsele_wp, + const std::string &sf_dependence, const std::string &variation_dm0, + const std::string &variation_dm1, const std::string &variation_dm10, + const std::string &variation_dm11); +ROOT::RDF::RNode +Id_vsJet(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::string &wp, const std::string &vsele_wp, + const std::string &sf_dependence, + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf); +ROOT::RDF::RNode Id_vsEle(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &eta, - const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::string &wp, - const std::string &era, - const std::string &variation_barrel, - const std::string &variation_endcap); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &eta, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::string &wp, const std::string &era, + const std::string &variation_barrel, + const std::string &variation_endcap); ROOT::RDF::RNode Id_vsMu(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &eta, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::string &wp, - const std::string &wp_ele, - const std::string &wp_jet, - const std::string &era, - const std::string &sf_vsmu_wheel1, - const std::string &sf_vsmu_wheel2, - const std::string &sf_vsmu_wheel3, - const std::string &sf_vsmu_wheel4, - const std::string &sf_vsmu_wheel5); + const std::string &outputname, const std::string &eta, + const std::string &gen_match, const std::string &sf_file, + const std::string &sf_name, const std::string &wp, + const std::string &wp_ele, const std::string &wp_jet, + const std::string &era, const std::string &sf_vsmu_wheel1, + const std::string &sf_vsmu_wheel2, const std::string &sf_vsmu_wheel3, + const std::string &sf_vsmu_wheel4, const std::string &sf_vsmu_wheel5); ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &sf_file, - const std::string &sf_name, - const std::string &trigger_name, const std::string &wp, - const std::string &corr_type, const std::string &variation); + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &sf_file, + const std::string &sf_name, const std::string &trigger_name, + const std::string &wp, const std::string &corr_type, + const std::string &variation); ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &trigger_flag, - const std::string &sf_file, - const std::string &sf_name, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &trigger_flag, + const std::string &sf_file, const std::string &sf_name, const std::string &trigger_name, const std::string &wp, const std::string &corr_type, const std::string &variation); } // end namespace scalefactor diff --git a/include/triggers.hxx b/include/triggers.hxx index 003dd5c4..e3eceed2 100644 --- a/include/triggers.hxx +++ b/include/triggers.hxx @@ -1,6 +1,8 @@ #ifndef GUARD_TRIGGERS_H #define GUARD_TRIGGERS_H +#include "utility/CorrectionManager.hxx" + typedef std::bitset<30> IntBits; namespace trigger { @@ -12,25 +14,26 @@ bool matchParticle(const ROOT::Math::PtEtaPhiMVector &particle, ROOT::RVec &triggerobject_ids, ROOT::RVec &triggerobject_filterbits, const float &pt_threshold, const float &eta_threshold, - const int &trigger_particle_id_value, const int &trigger_bit_value, - const float &deltaR_threshold); + const int &trigger_particle_id_value, + const int &trigger_bit_value, const float &deltaR_threshold); ROOT::RDF::RNode SingleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, - const std::string &triggerobject_id, const std::string &triggerobject_filterbit, - const std::string &hlt_path, const float &pt_threshold, const float &eta_threshold, + const std::string &triggerobject_id, + const std::string &triggerobject_filterbit, const std::string &hlt_path, + const float &pt_threshold, const float &eta_threshold, const int &trigger_particle_id_value, const int &trigger_bit_value, const float &deltaR_threshold); ROOT::RDF::RNode SingleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, - const std::string &triggerobject_id, const std::string &triggerobject_filterbit, - const float &pt_threshold, const float &eta_threshold, - const int &trigger_particle_id_value, const int &trigger_bit_value, - const float &deltaR_threshold); + const std::string &triggerobject_id, + const std::string &triggerobject_filterbit, const float &pt_threshold, + const float &eta_threshold, const int &trigger_particle_id_value, + const int &trigger_bit_value, const float &deltaR_threshold); ROOT::RDF::RNode DoubleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle_1, const std::string &particle_2, @@ -39,26 +42,25 @@ ROOT::RDF::RNode DoubleObjectFlag( const std::string &triggerobject_filterbit, const std::string &hlt_path, const float &pt_threshold_1, const float &pt_threshold_2, const float &eta_threshold_1, const float &eta_threshold_2, - const int &trigger_particle_id_value_1, const int &trigger_particle_id_value_2, - const int &trigger_bit_value_1, const int &trigger_bit_value_2, - const float &deltaR_threshold); + const int &trigger_particle_id_value_1, + const int &trigger_particle_id_value_2, const int &trigger_bit_value_1, + const int &trigger_bit_value_2, const float &deltaR_threshold); ROOT::RDF::RNode DoubleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle_1, const std::string &particle_2, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, const std::string &triggerobject_id, - const std::string &triggerobject_filterbit, - const float &pt_threshold_1, const float &pt_threshold_2, - const float &eta_threshold_1, const float &eta_threshold_2, - const int &trigger_particle_id_value_1, const int &trigger_particle_id_value_2, - const int &trigger_bit_value_1, const int &trigger_bit_value_2, - const float &deltaR_threshold); + const std::string &triggerobject_filterbit, const float &pt_threshold_1, + const float &pt_threshold_2, const float &eta_threshold_1, + const float &eta_threshold_2, const int &trigger_particle_id_value_1, + const int &trigger_particle_id_value_2, const int &trigger_bit_value_1, + const int &trigger_bit_value_2, const float &deltaR_threshold); -ROOT::RDF::RNode GetPrescaleValues( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &hlt_path, - const std::string &run, const std::string &lumiblock, - const std::string &prescale_file); +ROOT::RDF::RNode +GetPrescaleValues(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &hlt_path, + const std::string &run, const std::string &lumiblock, + const std::string &prescale_file); } // end namespace trigger #endif /* GUARD_TRIGGERS_H */ diff --git a/include/utility/Logger.hxx b/include/utility/Logger.hxx index 15319cdd..5ec18ba7 100644 --- a/include/utility/Logger.hxx +++ b/include/utility/Logger.hxx @@ -5,9 +5,9 @@ #include #include #include -#include // Include fmt library header #include #include +#include // Include fmt library header #include #include #include @@ -16,8 +16,8 @@ template <> struct fmt::formatter : fmt::formatter { // Use the format method of the std::string formatter template - auto format(const TString &tstring, - FormatContext &ctx) -> decltype(ctx.out()) { + auto format(const TString &tstring, FormatContext &ctx) + -> decltype(ctx.out()) { // Directly use the formatter for std::string on TString's value return fmt::formatter::format((std::string)tstring, ctx); } @@ -34,8 +34,8 @@ template struct fmt::formatter> { // Implement the format method to define how to convert // ROOT::VecOps::RVec to a string template - constexpr auto format(const ROOT::VecOps::RVec &vec, - FormatContext &ctx) -> decltype(ctx.out()) { + constexpr auto format(const ROOT::VecOps::RVec &vec, FormatContext &ctx) + -> decltype(ctx.out()) { // Start with an opening bracket fmt::format_to(ctx.out(), "["); // Format each element separated by a comma @@ -71,8 +71,8 @@ template <> struct fmt::formatter { // Generic formatter function for std::bitset of any size template struct BitsetFormatter { - static auto format(fmt::format_context &ctx, - const std::bitset &b) -> decltype(ctx.out()) { + static auto format(fmt::format_context &ctx, const std::bitset &b) + -> decltype(ctx.out()) { fmt::format_to(ctx.out(), "["); for (size_t i = 0; i < b.size(); ++i) { fmt::format_to(ctx.out(), "{}", b.test(i) ? '1' : '0'); @@ -85,8 +85,8 @@ template struct BitsetFormatter { template struct fmt::formatter> : formatter { template - auto format(const std::bitset &b, - FormatContext &ctx) -> decltype(ctx.out()) { + auto format(const std::bitset &b, FormatContext &ctx) + -> decltype(ctx.out()) { return BitsetFormatter::format(ctx, b); } }; diff --git a/include/utility/OnnxSessionManager.hxx b/include/utility/OnnxSessionManager.hxx index 3ff20c99..ba26ff5f 100644 --- a/include/utility/OnnxSessionManager.hxx +++ b/include/utility/OnnxSessionManager.hxx @@ -54,4 +54,4 @@ std::vector run_interference(Ort::Session *session, } // namespace onnxhelper -#endif /* GUARD_ONNX_SESSION_MANAGER */ \ No newline at end of file +#endif /* GUARD_ONNX_SESSION_MANAGER */ diff --git a/include/utility/utility.hxx b/include/utility/utility.hxx index 20de7528..0ddfffa7 100644 --- a/include/utility/utility.hxx +++ b/include/utility/utility.hxx @@ -15,43 +15,40 @@ namespace utility { /** - * @brief This function takes a column and casts it from type `I` to - * another type `O`. + * @brief This function takes a column and casts it from type `I` to + * another type `O`. * - * @note This functionality is mainly used to mitigate type changes + * @note This functionality is mainly used to mitigate type changes * between nanoAOD versions. * * @tparam O type of the output column * @tparam I type of the input column * @param df input dataframe - * @param outputname name of the output column containing the recasted + * @param outputname name of the output column containing the recasted * column - * @param outputtype string with the type of the output column - * @param column name of the column that should be recasted to another + * @param outputtype string with the type of the output column + * @param column name of the column that should be recasted to another * type * * @return a new dataframe with the new column */ -template -inline std::pair Cast(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &outputtype, - const std::string &column) { +template +inline std::pair +Cast(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &outputtype, const std::string &column) { auto new_df = df; auto new_col = column; auto inputtype = df.GetColumnType(column); - + if (inputtype != outputtype) { new_col = outputname; auto cols = df.GetColumnNames(); - // check if the column is already defined, this is relevant for systematic - // variations were this Define would be done multiple times + // check if the column is already defined, this is relevant for + // systematic variations were this Define would be done multiple times if (std::find(cols.begin(), cols.end(), outputname) == cols.end()) { new_df = df.Define( outputname, - [] (const I& values) { - return static_cast(values); - }, + [](const I &values) { return static_cast(values); }, {column}); } } @@ -85,20 +82,20 @@ inline bool ApproxEqual(double value1, double value2, double maxDelta = 1e-5) { } /** - * @brief This function extracts and returns the last element from a tuple - * containing a variable number of arguments. The function uses `std::get` - * to access the last element of the tuple, allowing you to retrieve the + * @brief This function extracts and returns the last element from a tuple + * containing a variable number of arguments. The function uses `std::get` + * to access the last element of the tuple, allowing you to retrieve the * last argument without knowing its type or index beforehand. * * @param args input tuple containing the arguments - * + * * @return last element of the tuple */ template -constexpr auto extractLastArgument(const std::tuple& args) { +constexpr auto extractLastArgument(const std::tuple &args) { constexpr size_t N = sizeof...(Args); // Extract last argument - return std::get(args); + return std::get(args); } /** @@ -112,7 +109,7 @@ constexpr auto extractLastArgument(const std::tuple& args) { * @return vector of strings with all elements except the last one */ template -constexpr auto popLastArgument(const std::tuple& args) { +constexpr auto popLastArgument(const std::tuple &args) { constexpr size_t N = sizeof...(Args); auto buildVector = [&](std::index_sequence) { return std::vector{std::get(args)...}; @@ -202,8 +199,8 @@ EvaluateWorkspaceFunction(ROOT::RDF::RNode df, const std::string &outputname, appendParameterPackToVector(InputList, inputs...); const auto nInputs = sizeof...(Inputs); Logger::get("EvaluateWorkspaceFunction")->debug("nInputs: {} ", nInputs); - auto df1 = df.Define( - outputname, PassAsVec(getValue), InputList); + auto df1 = + df.Define(outputname, PassAsVec(getValue), InputList); return df1; } } // end namespace utility diff --git a/init.sh b/init.sh index 7889ac60..2f1fed0e 100644 --- a/init.sh +++ b/init.sh @@ -1,91 +1,151 @@ #!/bin/bash -pathadd() { - if [[ ":$PATH:" != *":$1:"* ]]; then - PATH="${PATH:+"$PATH:"}$1" - export PATH + +action() { + + # --- Define list of available analyses --- + ANALYSIS_LIST=("tau" "earlyrun3" "whtautau" "boosted_h_tautau" "s" "xyh_bbtautau" "haa") + + # --- Define defaults --- + DEFAULT_CROWN_ANALYSIS="" + DEFAULT_CONTAINER="/cvmfs/unpacked.cern.ch/registry.hub.docker.com/kingmakerimages/kingmaker_standalone:V1" + DEFAULT_DRY_RUN=false + CROWN_ANALYSIS=${DEFAULT_CROWN_ANALYSIS} + CONTAINER=${DEFAULT_CONTAINER} + DRY_RUN=${DEFAULT_DRY_RUN} + + # --- Parse arguments --- + while [[ $# -gt 0 ]]; do + case $1 in + -a|--analysis) + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: --analysis requires a non-option argument." + return 1 + fi + CROWN_ANALYSIS="$2" + shift 2 + ;; + -c|--container) + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: --container requires a non-option argument." + return 1 + fi + CONTAINER="$2" + shift 2 + ;; + -d|--dry-run) + DRY_RUN=true + shift 1 + ;; + -l|--list) + echo "Available CROWN analyses:" + echo "-------------------" + for workflow in "${ANALYSIS_LIST[@]}"; do + echo "* ${workflow}" + done + return 1 + ;; + -h|--help) + echo "Usage: source setup.sh [options]" + echo "" + echo "Options:" + echo " -a, --analysis ANALYSIS The CROWN analysis configs to use" + echo " -c, --container CONTAINER The container to use as environment" + echo " 'none' initializes without starting a container" + echo " [default: ${DEFAULT_CONTAINER}]" + echo " -l, --list List available CROWN analyses" + echo " -d, --dry-run Only check out analysis configurations" + echo " -h, --help Show this help message" + echo "" + return 1 + ;; + *) + echo "Error: Unknown option $1" + echo "Use --help to see available options" + return 1 + ;; + esac + done + if [[ $? -eq "1" ]]; then + return 1 fi -} -# get the directory of the script -SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd 2>/dev/null)" -if ! command -v lsb_release &> /dev/null -then - source /etc/os-release - distro=$NAME - os_version=$VERSION_ID -else - distro=$(lsb_release -i | cut -f2) - os_version=$(lsb_release -r | cut -f2) -fi -distro=${distro//[[:space:]]/} -distro="${distro//Linux/}" -distro="${distro//linux/}" -echo "Setting up CROWN for $distro Version $os_version" -# check if the distro is centos -if [[ "$distro" == "CentOS" ]]; then - # if the first number of os_version is a 7, we are on centOS 7 - if [[ ${os_version:0:1} == "7" ]]; then # if uname -a | grep -E 'el7' -q - echo "CentOS 7 is EOL, running on LCG 105, support will be dropped soon" - source /cvmfs/sft.cern.ch/lcg/views/LCG_105/x86_64-centos7-gcc11-opt/setup.sh - else - echo "Unsupported CentOS version, exiting..." - return 0 + + # --- Local Path Setup --- + SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd 2>/dev/null)" + ANALYSIS_PATH="${SCRIPT_DIR}" + + # --- Clone Analysis Logic (if second arg is provided) --- + if [ -n "${CROWN_ANALYSIS}" ]; then + case "${CROWN_ANALYSIS}" in + tau) REPO="git@github.com:KIT-CMS/TauAnalysis-CROWN.git" ;; + earlyrun3) REPO="git@github.com:KIT-CMS/earlyRun3Analysis-CROWN" ;; + whtautau) REPO="git@github.com:KIT-CMS/WHTauTauAnalysis-CROWN.git" ;; + boosted_h_tautau) REPO="git@github.com:KIT-CMS/BoostedHiggsTauTauAnalysis-CROWN.git" ;; + s) REPO="git@github.com:nfaltermann/CROWNs.git" ;; + xyh_bbtautau) REPO="git@github.com:KIT-CMS/XYHBBTauTauAnalysis-CROWN.git" ;; + haa) REPO="git@github.com:KIT-CMS/HaaAnalysis-CROWN.git" ;; + *) echo "Error: '${CROWN_ANALYSIS}' is not a valid analysis name." + echo "See --list argument for available analyses." + return 1 + ;; + esac + + if [ -n "${REPO}" ] && [ ! -d "${SCRIPT_DIR}/analysis_configurations/${CROWN_ANALYSIS}" ]; then + echo "--> Cloning analysis ${CROWN_ANALYSIS}..." + git clone "${REPO}" "${SCRIPT_DIR}/analysis_configurations/${CROWN_ANALYSIS}" + else + echo "--> Analysis configuration '${CROWN_ANALYSIS}' already exists." + fi fi -elif [[ "$distro" == "RedHatEnterprise" || "$distro" == "Alma" || "$distro" == "Rocky" ]]; then - if [[ ${os_version:0:1} == "8" ]]; then # elif uname -a | grep -E 'el8' -q - echo "Unsupported CentOS version, exiting..." - return 0 - elif [[ ${os_version:0:1} == "9" ]]; then # elif uname -a | grep -E 'el8' -q - source /cvmfs/sft.cern.ch/lcg/views/LCG_108/x86_64-el9-gcc15-opt/setup.sh - else - echo "Unsupported CentOS version, exiting..." - return 0 + + # --- Dry Run Exit Point --- + if [ "${DRY_RUN}" = true ]; then + echo "--> Dry run complete. Analysis configs are ready." + return 0 2>/dev/null || exit 0 fi -elif [[ "$distro" == "Ubuntu" ]]; then - if [[ ${os_version:0:2} == "20" ]]; then - source /cvmfs/sft.cern.ch/lcg/views/LCG_106/x86_64-ubuntu2004-gcc9-opt/setup.sh - elif [[ ${os_version:0:2} == "22" ]]; then - source /cvmfs/sft.cern.ch/lcg/views/LCG_106/x86_64-ubuntu2204-gcc11-opt/setup.sh - else - echo "Unsupported Ubuntu version, exiting..." - return 0 + + # --- VOMS Proxy Check --- + if ! voms-proxy-info -exists -file "${X509_USER_PROXY}" >/dev/null 2>&1; then + echo "Warning: No valid VOMS proxy found. Grid storage may be inaccessible." fi -else - echo "You are not running on CentOS or Ubuntu, exiting..." - return 0 -fi -# add ~/.local/bin to path if it is not already there -pathadd "${HOME}/.local/bin/" -# set the cmake generator to Ninja -# export CMAKE_GENERATOR="Ninja" -export CMAKE_GENERATOR="Unix Makefiles" -# set the compiler optimization for cling to O2, this -# will result in about 20% faster JIT for the snapshot generation -export EXTRA_CLING_ARGS='-O2' -# clone a given analysis if an argument is given -if [ -z "$1" ]; then - echo "No configuration clone" -else - if [[ "$1" == "tau" && ! -d "${SCRIPT_DIR}/analysis_configurations/tau" ]]; then - echo "Cloning analysis tau into ${SCRIPT_DIR}/analysis_configurations/tau" - git clone git@github.com:KIT-CMS/TauAnalysis-CROWN.git "${SCRIPT_DIR}/analysis_configurations/tau" - elif [[ "$1" == "earlyrun3" && ! -d "${SCRIPT_DIR}/analysis_configurations/earlyrun3" ]]; then - echo "Cloning analysis earlyrun3 into ${SCRIPT_DIR}/analysis_configurations/earlyrun3" - git clone https://github.com/KIT-CMS/earlyRun3Analysis-CROWN "${SCRIPT_DIR}/analysis_configurations/earlyrun3" - elif [[ "$1" == "whtautau" && ! -d "${SCRIPT_DIR}/analysis_configurations/whtautau" ]]; then - echo "Cloning analysis whtautau into ${SCRIPT_DIR}/analysis_configurations/whtautau" - git clone git@github.com:KIT-CMS/WHTauTauAnalysis-CROWN.git "${SCRIPT_DIR}/analysis_configurations/whtautau" - elif [[ "$1" == "boosted_h_tautau" && ! -d "${SCRIPT_DIR}/analysis_configurations/boosted_h_tautau" ]]; then - echo "Cloning analysis boosted_h_tautau into ${SCRIPT_DIR}/analysis_configurations/boosted_h_tautau" - git clone git@github.com:KIT-CMS/BoostedHiggsTauTauAnalysis-CROWN.git "${SCRIPT_DIR}/analysis_configurations/boosted_h_tautau" - elif [[ "$1" == "s" && ! -d "${SCRIPT_DIR}/analysis_configurations/s" ]]; then - echo "Cloning analysis s-channel into ${SCRIPT_DIR}/analysis_configurations/s" - git clone git@github.com:nfaltermann/CROWNs.git "${SCRIPT_DIR}/analysis_configurations/s" - elif [[ "$1" == "xyh_bbtautau" && ! -d "${SCRIPT_DIR}/analysis_configurations/xyh_bbtautau" ]]; then - echo "Cloning analysis XYHbbtautau into ${SCRIPT_DIR}/analysis_configurations/xyh_bbtautau" - git clone git@github.com:KIT-CMS/XYHBBTauTauAnalysis-CROWN.git "${SCRIPT_DIR}/analysis_configurations/xyh_bbtautau" - elif [[ "$1" == "haa" && ! -d "${SCRIPT_DIR}/analysis_configurations/haa" ]]; then - echo "Cloning analysis Haa into ${SCRIPT_DIR}/analysis_configurations/haa" - git clone git@github.com:KIT-CMS/HaaAnalysis-CROWN.git "${SCRIPT_DIR}/analysis_configurations/haa" + if [[ "$CONTAINER" == "none" ]]; then + # Only set env variables if container is set to "none" + # Requires local environment to function + echo '--- Initializing Local Environment ---'; + export ANALYSIS_PATH + export CROWN_ANALYSIS + export CCACHE_DIR=${ANALYSIS_PATH}/.cache/ccache; + export CMAKE_GENERATOR='Unix Makefiles'; + export EXTRA_CLING_ARGS='-O2'; + elif [[ "$CONTAINER" == "lcg" ]]; then + echo "Initializing LCG stack environment..." + source /cvmfs/sft.cern.ch/lcg/views/LCG_108/x86_64-el9-gcc15-opt/setup.sh + else + # --- Get the absolute path of the parent git repository --- + # checks/git-status.sh fails if top level git directory is not mounted in + GIT_ROOT=$(git -C "${SCRIPT_DIR}" rev-parse --show-superproject-working-tree) + + # --- Define the Internal Environment --- + # This string is executed once the container starts + INT_CMD=" + echo '--- Initializing Container Environment ---'; + export ANALYSIS_PATH=${ANALYSIS_PATH}; + export CROWN_ANALYSIS=${CROWN_ANALYSIS}; + export CCACHE_DIR=${ANALYSIS_PATH}/.cache/ccache; + export CMAKE_GENERATOR='Unix Makefiles'; + export EXTRA_CLING_ARGS='-O2'; + export X509_USER_PROXY=${X509_USER_PROXY}; + bash --rcfile /etc/bashrc -i + " + + # --- Execute Singularity --- + echo "--> Launching Container: ${CONTAINER}" + singularity exec -e \ + -B /etc/grid-security/certificates \ + -B "${GIT_ROOT}:${GIT_ROOT}" \ + -B "${HOME}:${HOME}" \ + "${CONTAINER}" \ + bash -c "${INT_CMD}" fi -fi +} +action "$@" diff --git a/src/electrons.cxx b/src/electrons.cxx index f197455a..2c3a1b7a 100644 --- a/src/electrons.cxx +++ b/src/electrons.cxx @@ -56,12 +56,9 @@ PtCorrectionMC(ROOT::RDF::RNode df, const std::string &eta, const std::string &seed_gain, const std::string &es_resolution_up, const std::string &es_resolution_down, - const std::string &es_file, - const std::string &es_name, - const std::string &era, - const std::string &variation) { - auto evaluator = - correction_manager.loadCorrection(es_file, es_name); + const std::string &es_file, const std::string &es_name, + const std::string &era, const std::string &variation) { + auto evaluator = correction_manager.loadCorrection(es_file, es_name); auto electron_pt_correction_lambda = [evaluator, era, variation](const ROOT::RVec &pts, const ROOT::RVec &etas, @@ -86,9 +83,9 @@ PtCorrectionMC(ROOT::RDF::RNode df, Logger::get("physicsobject::electron::PtCorrectionMC") ->debug("inputs: era {}, eta {}, seed gain {}", era, etas.at(i), static_cast(seed_gains.at(i))); - auto sf = - evaluator->evaluate({era, "scaleup", etas.at(i), - static_cast(seed_gains.at(i))}); + auto sf = evaluator->evaluate( + {era, "scaleup", etas.at(i), + static_cast(seed_gains.at(i))}); corrected_pts[i] = pts.at(i) * sf; Logger::get("physicsobject::electron::PtCorrectionMC") ->debug("ele pt before {}, ele pt after {}, sf {}", @@ -97,9 +94,9 @@ PtCorrectionMC(ROOT::RDF::RNode df, Logger::get("physicsobject::electron::PtCorrectionMC") ->debug("inputs: era {}, eta {}, seed gain {}", era, etas.at(i), static_cast(seed_gains.at(i))); - auto sf = - evaluator->evaluate({era, "scaledown", etas.at(i), - static_cast(seed_gains.at(i))}); + auto sf = evaluator->evaluate( + {era, "scaledown", etas.at(i), + static_cast(seed_gains.at(i))}); corrected_pts[i] = pts.at(i) * sf; Logger::get("physicsobject::electron::PtCorrectionMC") ->debug("ele pt before {}, ele pt after {}, sf {}", @@ -113,27 +110,32 @@ PtCorrectionMC(ROOT::RDF::RNode df, } return corrected_pts; }; - auto df1 = df.Define(outputname, electron_pt_correction_lambda, - {pt, eta, seed_gain, es_resolution_up, es_resolution_down}); + auto df1 = + df.Define(outputname, electron_pt_correction_lambda, + {pt, eta, seed_gain, es_resolution_up, es_resolution_down}); return df1; } /** * @brief This function applies energy scale and resolution corrections to MC. * The corrections are obtained from a dedicated correctionlib file. - * + * * For Run 3 samples, the electron energy scale correction has to be evaluated * using a centrally provided correctionlib file. The documentation of the file * content can be found here: - * - * - [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronSS_EtDependent.html) - * - [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronSS_EtDependent.html) - * - [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronSS_EtDependent.html) - * - [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronSS_EtDependent.html) + * + * - + * [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronSS_EtDependent.html) + * - + * [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronSS_EtDependent.html) + * - + * [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronSS_EtDependent.html) + * - + * [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronSS_EtDependent.html) * * An implementation recipe is provided here: * [egmScaleAndSmearingExample.py](https://gitlab.cern.ch/cms-nanoAOD/jsonpog-integration/-/blob/master/examples/egmScaleAndSmearingExample.py). - * + * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction scale uncertainty patch file @@ -155,7 +157,7 @@ PtCorrectionMC(ROOT::RDF::RNode df, * for "nominal" nothing is done because energy correction is already applied * * @return a dataframe containing the varied electron transverse momenta - * + * * @note This function is intended for analyses working with Run 3 NanoAODv12 * or higher. In the Run 2 samples, the scale correction in data * is already applied in the NanoAOD files. Look at the overloaded version of @@ -165,26 +167,21 @@ ROOT::RDF::RNode PtCorrectionMC(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, const std::string &outputname, const std::string &pt, - const std::string &eta, - const std::string &delta_eta_sc, - const std::string &r9, - const std::string &event_seed, - const std::string &sf_file, - const std::string &sf_name, + const std::string &eta, const std::string &delta_eta_sc, + const std::string &r9, const std::string &event_seed, + const std::string &sf_file, const std::string &sf_name, const std::string &variation) { // load corrections - auto evaluator = - correction_manager.loadCorrection(sf_file, sf_name); + auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); // lambda function to apply the scale and smearing corrections - auto correction = [evaluator, variation] ( - const ROOT::RVec &pt, - const ROOT::RVec &eta, - const ROOT::RVec &delta_eta_sc, - const ROOT::RVec &r9, - const unsigned int &event_seed - ) { + auto correction = [evaluator, + variation](const ROOT::RVec &pt, + const ROOT::RVec &eta, + const ROOT::RVec &delta_eta_sc, + const ROOT::RVec &r9, + const unsigned int &event_seed) { // initialize the random number generator with the event seed TRandom3 rand_gen = TRandom3(event_seed); @@ -196,28 +193,16 @@ PtCorrectionMC(ROOT::RDF::RNode df, // calculate the nominal corrected pt by smearing the original pt auto random_number = rand_gen.Gaus(0.0, 1.0); - auto smear_nom = evaluator->evaluate({ - "smear", - pt.at(i), - r9.at(i), - eta_sc - }); + auto smear_nom = + evaluator->evaluate({"smear", pt.at(i), r9.at(i), eta_sc}); // get the scale uncertainty - auto scale_unc = evaluator->evaluate({ - "escale", - pt.at(i), - r9.at(i), - eta_sc - }); + auto scale_unc = + evaluator->evaluate({"escale", pt.at(i), r9.at(i), eta_sc}); // get the resolution uncertainty - auto smear_unc = evaluator->evaluate({ - "esmear", - pt.at(i), - r9.at(i), - eta_sc - }); + auto smear_unc = + evaluator->evaluate({"esmear", pt.at(i), r9.at(i), eta_sc}); // set the corrected pt based on the considered variation float sf = 1.0; @@ -225,10 +210,12 @@ PtCorrectionMC(ROOT::RDF::RNode df, sf = std::max(0.0, 1.0 + smear_nom * random_number); pt_corrected[i] = pt.at(i) * sf; } else if (variation == "resolutionUp") { - sf = std::max(0.0, 1.0 + (smear_nom + smear_unc) * random_number); + sf = std::max(0.0, + 1.0 + (smear_nom + smear_unc) * random_number); pt_corrected[i] = pt.at(i) * sf; } else if (variation == "resolutionDown") { - sf = std::max(0.0, 1.0 + (smear_nom - smear_unc) * random_number); + sf = std::max(0.0, + 1.0 + (smear_nom - smear_unc) * random_number); pt_corrected[i] = pt.at(i) * sf; } else if (variation == "scaleUp") { sf = 1.0 + scale_unc; @@ -244,38 +231,39 @@ PtCorrectionMC(ROOT::RDF::RNode df, // logging output Logger::get("physicsobject::electron::PtCorrectionMC") - ->debug("ele pt before {}, ele pt after {}, sf {}, variation {}", - pt.at(i), pt_corrected.at(i), sf, variation); - + ->debug( + "ele pt before {}, ele pt after {}, sf {}, variation {}", + pt.at(i), pt_corrected.at(i), sf, variation); } return pt_corrected; }; - return df.Define( - outputname, - correction, - {pt, eta, delta_eta_sc, r9, event_seed} - ); + return df.Define(outputname, correction, + {pt, eta, delta_eta_sc, r9, event_seed}); } /** - * @brief This function applies energy scale corrections to data. The corrections are - * obtained from a dedicated correctionlib file. - * - * For Run 3 samples, the electron scale correction is not available in the NanoAOD files - * and the corrections have to be evaluated using a centrally provided correctionlib file. - * This function should only be used The documentation of the file content - * can be found here: - * - * - [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronSS_EtDependent.html) - * - [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronSS_EtDependent.html) - * - [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronSS_EtDependent.html) - * - [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronSS_EtDependent.html) + * @brief This function applies energy scale corrections to data. The + * corrections are obtained from a dedicated correctionlib file. + * + * For Run 3 samples, the electron scale correction is not available in the + * NanoAOD files and the corrections have to be evaluated using a centrally + * provided correctionlib file. This function should only be used The + * documentation of the file content can be found here: + * + * - + * [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronSS_EtDependent.html) + * - + * [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronSS_EtDependent.html) + * - + * [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronSS_EtDependent.html) + * - + * [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronSS_EtDependent.html) * * An implementation recipe is provided here: * [egmScaleAndSmearingExample.py](https://gitlab.cern.ch/cms-nanoAOD/jsonpog-integration/-/blob/master/examples/egmScaleAndSmearingExample.py). - * + * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction scale uncertainty patch file @@ -294,59 +282,49 @@ PtCorrectionMC(ROOT::RDF::RNode df, * for "nominal" nothing is done because energy correction is already applied * * @return a dataframe containing the varied electron transverse momenta - * + * * @note This function is intended for analyses working with Run 3. */ ROOT::RDF::RNode PtCorrectionData(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &delta_eta_sc, - const std::string &seed_gain, - const std::string &r9, const std::string &run, - const std::string &sf_file, - const std::string &sf_name) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &delta_eta_sc, + const std::string &seed_gain, const std::string &r9, + const std::string &run, const std::string &sf_file, + const std::string &sf_name) { // load the correctionlib evaluator auto evaluator = correction_manager.loadCompoundCorrection(sf_file, sf_name); // lambda function to apply the scale correction - auto correction = [evaluator] ( - const ROOT::RVec &pt, - const ROOT::RVec &eta, - const ROOT::RVec &delta_eta_sc, - const ROOT::RVec &seed_gain, - const ROOT::RVec &r9, - const unsigned int &run - ) { - // for the data correction, we just need to multiply the original pt with the scale factor - ROOT::RVec corrected_pt(pt.size()); - for (int i = 0; i < pt.size(); ++i) { - // calculate supercluster eta - float eta_sc = eta.at(i) + delta_eta_sc.at(i); + auto correction = + [evaluator](const ROOT::RVec &pt, const ROOT::RVec &eta, + const ROOT::RVec &delta_eta_sc, + const ROOT::RVec &seed_gain, + const ROOT::RVec &r9, const unsigned int &run) { + // for the data correction, we just need to multiply the original pt + // with the scale factor + ROOT::RVec corrected_pt(pt.size()); + for (int i = 0; i < pt.size(); ++i) { + // calculate supercluster eta + float eta_sc = eta.at(i) + delta_eta_sc.at(i); - // evaluate the nominal correction scale factor from correctionlib - auto sf = evaluator->evaluate({ - "scale", - static_cast(run), - eta_sc, - r9.at(i), - pt.at(i), - static_cast(seed_gain.at(i)) - }); - corrected_pt[i] = sf * pt.at(i); - Logger::get("physicsobject::electron::PtCorrectionData") - ->debug("ele pt before {}, ele pt after {}, sf {}", - pt.at(i), corrected_pt.at(i), sf); - } - return corrected_pt; - }; + // evaluate the nominal correction scale factor from + // correctionlib + auto sf = evaluator->evaluate( + {"scale", static_cast(run), eta_sc, r9.at(i), + pt.at(i), static_cast(seed_gain.at(i))}); + corrected_pt[i] = sf * pt.at(i); + Logger::get("physicsobject::electron::PtCorrectionData") + ->debug("ele pt before {}, ele pt after {}, sf {}", + pt.at(i), corrected_pt.at(i), sf); + } + return corrected_pt; + }; - return df.Define( - outputname, - correction, - {pt, eta, delta_eta_sc, seed_gain, r9, run} - ); + return df.Define(outputname, correction, + {pt, eta, delta_eta_sc, seed_gain, r9, run}); } /** @@ -433,7 +411,7 @@ namespace scalefactor { /** * @brief This function calculates electron ID scale factors (SFs) for a single * electron dependening on its pseudorapidity (\f$\eta\f$) and transverse - * momentum (\f$p_T\f$). The scale factors are loaded from a correctionlib file + * momentum (\f$p_T\f$). The scale factors are loaded from a correctionlib file * using a specified scale factor name and variation. * * Recommendations by EgammaPOG: @@ -461,15 +439,15 @@ namespace scalefactor { * @return a new dataframe containing the new column * * @note This function needs the dependence on phi only in case of 2023 data - * because for whatever reason EGM POG introduced it only in that era. + * because for whatever reason EGM POG introduced it only in that era. */ ROOT::RDF::RNode Id(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, const std::string &outputname, const std::string &pt, const std::string &eta, const std::string &phi, - const std::string &era, - const std::string &wp, const std::string &sf_file, - const std::string &sf_name, const std::string &variation) { + const std::string &era, const std::string &wp, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation) { Logger::get("physicsobject::electron::scalefactor::Id") ->debug("Setting up functions for electron id sf with correctionlib"); Logger::get("physicsobject::electron::scalefactor::Id") @@ -477,9 +455,8 @@ ROOT::RDF::RNode Id(ROOT::RDF::RNode df, auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); auto df1 = df.Define( outputname, - [evaluator, era, sf_name, wp, variation](const float &pt, - const float &eta, - const float &phi) { + [evaluator, era, sf_name, wp, + variation](const float &pt, const float &eta, const float &phi) { Logger::get("physicsobject::electron::scalefactor::Id") ->debug("Era {}, Variation {}, WP {}", era, variation, wp); Logger::get("physicsobject::electron::scalefactor::Id") @@ -488,9 +465,10 @@ ROOT::RDF::RNode Id(ROOT::RDF::RNode df, if (pt >= 0.0) { if (era.find("2023") != std::string::npos) { // for 2023, phi is needed as input - sf = evaluator->evaluate({era, variation, wp, eta, pt, phi}); - } - else sf = evaluator->evaluate({era, variation, wp, eta, pt}); + sf = + evaluator->evaluate({era, variation, wp, eta, pt, phi}); + } else + sf = evaluator->evaluate({era, variation, wp, eta, pt}); } Logger::get("physicsobject::electron::scalefactor::Id") ->debug("Scale Factor {}", sf); @@ -502,22 +480,28 @@ ROOT::RDF::RNode Id(ROOT::RDF::RNode df, /** * @brief This function calculates single electron trigger scale factors (SFs) - * for a single electron dependening on its pseudorapidity (\f$\eta\f$), its transverse - * momentum (\f$p_T\f$), and the electron identification working point. The scale factors - * are loaded from a correctionlib file using a specified scale factor name and variation. - * This function only uses the scale factor from the correctionlib evaluation if the - * corresponding trigger flag is set to `true`. Otherwise, it returns a scale factor of - * 1.0. + * for a single electron dependening on its pseudorapidity (\f$\eta\f$), its + * transverse momentum (\f$p_T\f$), and the electron identification working + * point. The scale factors are loaded from a correctionlib file using a + * specified scale factor name and variation. This function only uses the scale + * factor from the correctionlib evaluation if the corresponding trigger flag is + * set to `true`. Otherwise, it returns a scale factor of 1.0. * * Recommendations by EgammaPOG: - * - [Run3 triggers](https://twiki.cern.ch/twiki/bin/view/CMS/EgHLTRunIIISummary) - * - [Run3 scale factors](https://twiki.cern.ch/twiki/bin/view/CMS/EgammSFandSSRun3) - * + * - [Run3 + * triggers](https://twiki.cern.ch/twiki/bin/view/CMS/EgHLTRunIIISummary) + * - [Run3 scale + * factors](https://twiki.cern.ch/twiki/bin/view/CMS/EgammSFandSSRun3) + * * The documentation of the corresponding jsonPOG files can be found here: - * - [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronHlt.html) - * - [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronHlt.html) - * - [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronHlt.html) - * - [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronHlt.html) + * - + * [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22_electronHlt.html) + * - + * [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2022_Summer22EE_electronHlt.html) + * - + * [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23_electronHlt.html) + * - + * [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/EGM_2023_Summer23BPix_electronHlt.html) * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -540,15 +524,17 @@ ROOT::RDF::RNode Id(ROOT::RDF::RNode df, * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &trigger_flag, - const std::string &era, const std::string &path_id_name, - const std::string &sf_file, const std::string &sf_name, - const std::string &variation) { +ROOT::RDF::RNode +Trigger(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &trigger_flag, + const std::string &era, const std::string &path_id_name, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation) { Logger::get("physicsobject::electron::scalefactor::Trigger") - ->debug("Setting up functions for electron trigger sf with correctionlib"); + ->debug( + "Setting up functions for electron trigger sf with correctionlib"); Logger::get("physicsobject::electron::scalefactor::Trigger") ->debug("Scale factor - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); @@ -557,15 +543,18 @@ ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, [evaluator, era, sf_name, path_id_name, variation]( const float &pt, const float &eta, const bool &trigger_flag) { Logger::get("physicsobject::electron::scalefactor::Trigger") - ->debug("Era {}, Variation {}, Trigger at electron ID {}", era, variation, path_id_name); + ->debug("Era {}, Variation {}, Trigger at electron ID {}", era, + variation, path_id_name); Logger::get("physicsobject::electron::scalefactor::Trigger") - ->debug("ID - pt {}, eta {}, trigger flag {}", pt, eta, trigger_flag); + ->debug("ID - pt {}, eta {}, trigger flag {}", pt, eta, + trigger_flag); double sf = 1.; // check to prevent electrons with default values due to tau energy // correction shifts below good tau pt selection try { if (pt >= 0.0 && std::abs(eta) >= 0.0 && trigger_flag) { - sf = evaluator->evaluate({era, variation, path_id_name, eta, pt}); + sf = evaluator->evaluate( + {era, variation, path_id_name, eta, pt}); Logger::get("physicsobject::electron::scalefactor::Trigger") ->debug("Scale Factor {}", sf); } diff --git a/src/embedding.cxx b/src/embedding.cxx index e55596aa..0a4f4a7a 100644 --- a/src/embedding.cxx +++ b/src/embedding.cxx @@ -12,108 +12,107 @@ namespace embedding { namespace scalefactor { /** - * @brief This function calculates a scale factor (SF) that corrects the bias - * in the trigger selection of events for the embedding method. The scale factors - * are measured by the tau embedding group and are loaded from a correctionlib - * file using a specified scale factor name. + * @brief This function calculates a scale factor (SF) that corrects the bias + * in the trigger selection of events for the embedding method. The scale + * factors are measured by the tau embedding group and are loaded from a + * correctionlib file using a specified scale factor name. * - * For the calculation the two initially selected muons in data need to be + * For the calculation the two initially selected muons in data need to be * provided. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file - * @param outputname name of the output column containing the embedding + * @param outputname name of the output column containing the embedding * selection trigger scale factor - * @param pt_1 \f$p_T\f$ of the leading generator particle which corresponds + * @param pt_1 \f$p_T\f$ of the leading generator particle which corresponds * to the leading muon selected by the embedding selection - * @param eta_1 \f$\eta\f$ of the leading generator particle which corresponds + * @param eta_1 \f$\eta\f$ of the leading generator particle which corresponds * to the leading muon selected by the embedding selection - * @param pt_2 \f$p_T\f$ of the subleading generator particle which corresponds - * to the subleading muon selected by the embedding selection - * @param eta_2 \f$\eta\f$ of the subleading generator particle which corresponds + * @param pt_2 \f$p_T\f$ of the subleading generator particle which corresponds * to the subleading muon selected by the embedding selection - * @param sf_file path to the file with the embedding selection trigger scale + * @param eta_2 \f$\eta\f$ of the subleading generator particle which + * corresponds to the subleading muon selected by the embedding selection + * @param sf_file path to the file with the embedding selection trigger scale * factors - * @param sf_name name of the embedding selection trigger scale factor correction - * e.g. "m_sel_trg_kit_ratio" + * @param sf_name name of the embedding selection trigger scale factor + * correction e.g. "m_sel_trg_kit_ratio" * * @return a new dataframe containing the new column */ ROOT::RDF::RNode SelectionTrigger(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt_1, const std::string &eta_1, - const std::string &pt_2, const std::string &eta_2, - const std::string &sf_file, - const std::string &sf_name) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt_1, + const std::string &eta_1, const std::string &pt_2, + const std::string &eta_2, const std::string &sf_file, + const std::string &sf_name) { Logger::get("embedding::scalefactor::SelectionTrigger") ->debug("Correction - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto df1 = df.Define( - outputname, - [evaluator](const float &pt_1, const float &eta_1, const float &pt_2, - const float &eta_2) { - Logger::get("embedding::scalefactor::SelectionTrigger") - ->debug(" pt_1 {}, eta_1 {}, pt_2 {}, eta_2 {}", pt_1, eta_1, - pt_2, eta_2); - double sf = 1.; - sf = evaluator->evaluate( - {pt_1, std::abs(eta_1), pt_2, std::abs(eta_2)}); - Logger::get("embedding::scalefactor::SelectionTrigger")->debug("sf {}", sf); - return sf; - }, - {pt_1, eta_1, pt_2, eta_2}); + auto df1 = + df.Define(outputname, + [evaluator](const float &pt_1, const float &eta_1, + const float &pt_2, const float &eta_2) { + Logger::get("embedding::scalefactor::SelectionTrigger") + ->debug(" pt_1 {}, eta_1 {}, pt_2 {}, eta_2 {}", pt_1, + eta_1, pt_2, eta_2); + double sf = 1.; + sf = evaluator->evaluate( + {pt_1, std::abs(eta_1), pt_2, std::abs(eta_2)}); + Logger::get("embedding::scalefactor::SelectionTrigger") + ->debug("sf {}", sf); + return sf; + }, + {pt_1, eta_1, pt_2, eta_2}); return df1; } /** - * @brief This function calculates a scale factor (SF) that corrects the bias - * in the ID selection of muons in events for the embedding method. The scale - * factors are measured by the tau embedding group and are loaded from a + * @brief This function calculates a scale factor (SF) that corrects the bias + * in the ID selection of muons in events for the embedding method. The scale + * factors are measured by the tau embedding group and are loaded from a * correctionlib file using a specified scale factor name. * - * For the calculation the one of the two initially selected muons in data + * For the calculation the one of the two initially selected muons in data * need to be provided. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file - * @param outputname name of the output column containing the embedding + * @param outputname name of the output column containing the embedding * selection ID scale factor * @param pt \f$p_T\f$ of a generator particle which corresponds to * one of the muons selected by the embedding selection * @param eta \f$\eta\f$ of a generator particle which corresponds to * one of the muons selected by the embedding selection - * @param sf_file tpath to the file with the embedding selection ID scale + * @param sf_file tpath to the file with the embedding selection ID scale * factors - * @param sf_name name of the embedding selection trigger scale factor correction - * e.g. "EmbID_pt_eta_bins" + * @param sf_name name of the embedding selection trigger scale factor + * correction e.g. "EmbID_pt_eta_bins" * * @return a new dataframe containing the new column */ ROOT::RDF::RNode SelectionId(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &eta, - const std::string &sf_file, - const std::string &sf_name) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name) { Logger::get("embedding::scalefactor::SelectionId") ->debug("Correction - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto df1 = - df.Define(outputname, - [evaluator](const float &pt, const float &eta) { - Logger::get("embedding::scalefactor::SelectionId") - ->debug(" pt {}, eta {},", pt, eta); - double sf = 1.; - sf = evaluator->evaluate({pt, std::abs(eta)}); - Logger::get("embedding::scalefactor::SelectionId")->debug("sf {}", sf); - return sf; - }, - {pt, eta}); + auto df1 = df.Define(outputname, + [evaluator](const float &pt, const float &eta) { + Logger::get("embedding::scalefactor::SelectionId") + ->debug(" pt {}, eta {},", pt, eta); + double sf = 1.; + sf = evaluator->evaluate({pt, std::abs(eta)}); + Logger::get("embedding::scalefactor::SelectionId") + ->debug("sf {}", sf); + return sf; + }, + {pt, eta}); return df1; } } // end namespace scalefactor @@ -121,16 +120,16 @@ SelectionId(ROOT::RDF::RNode df, namespace muon { /** - * @brief This function calculates muon scale factors (SFs) that were - * measured by the tau embedding group for embedding samples. The scale factors - * are loaded from a correctionlib file using a specified scale factor name + * @brief This function calculates muon scale factors (SFs) that were + * measured by the tau embedding group for embedding samples. The scale factors + * are loaded from a correctionlib file using a specified scale factor name * which defines the correction (e.g. ID, Iso, Trigger). * * The tau embedding group also measured muon scale factors for simulated - * samples with the same T&P method as for embedding. Which scale factor is + * samples with the same T&P method as for embedding. Which scale factor is * used can be specified by the `correction_type` parameter. * - * The variation is introduced via an extrapolation factor. This factor is + * The variation is introduced via an extrapolation factor. This factor is * applied on top of the scale factor, thereby varying the scale factor by a * fixed percentage. * @@ -143,9 +142,9 @@ namespace muon { * @param sf_file path to the file containing the muon scale factors * @param sf_name name of the muon scale factor correction, this parameter * defines what is corrected ID, Iso or Trigger, e.g. "Trg_IsoMu27_pt_eta_bins" - * @param correction_type type of the correction, there are two options: `emb` + * @param correction_type type of the correction, there are two options: `emb` * for embedding and `mc` for simulation - * @param extrapolation_factor factor that is used to introduce percent type + * @param extrapolation_factor factor that is used to introduce percent type * variations of the scale factor, default value is `1.0` * * @return a new dataframe containing the new column @@ -156,19 +155,19 @@ namespace muon { */ ROOT::RDF::RNode Scalefactor(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &eta, - const std::string &sf_file, const std::string &sf_name, - const std::string correction_type, - const float &extrapolation_factor = 1.0) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name, const std::string correction_type, + const float &extrapolation_factor = 1.0) { - Logger::get("embedding::muon::Scalefactor")->debug("Correction - Name {}", sf_name); + Logger::get("embedding::muon::Scalefactor") + ->debug("Correction - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); auto df1 = df.Define( outputname, [evaluator, correction_type, extrapolation_factor](const float &pt, - const float &eta) { + const float &eta) { Logger::get("embedding::muon::Scalefactor") ->debug(" pt {}, eta {}, correction_type {}, extrapolation " "factor {}", @@ -290,31 +289,33 @@ PtCorrection(ROOT::RDF::RNode df, } /** - * @brief This function calculates electron scale factors (SFs) that were - * measured by the tau embedding group for embedding samples. The scale factors - * are loaded from a correctionlib file using a specified scale factor name + * @brief This function calculates electron scale factors (SFs) that were + * measured by the tau embedding group for embedding samples. The scale factors + * are loaded from a correctionlib file using a specified scale factor name * which defines the correction (e.g. ID, Iso, Trigger). * * The tau embedding group also measured electron scale factors for simulated - * samples with the same T&P method as for embedding. Which scale factor is + * samples with the same T&P method as for embedding. Which scale factor is * used can be specified by the `correction_type` parameter. * - * The variation is introduced via an extrapolation factor. This factor is + * The variation is introduced via an extrapolation factor. This factor is * applied on top of the scale factor, thereby varying the scale factor by a * fixed percentage. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * electron scale factor file - * @param outputname name of the output column containing the electron scale factor - * @param pt name of the column containing the transverse momentum of an electron + * @param outputname name of the output column containing the electron scale + * factor + * @param pt name of the column containing the transverse momentum of an + * electron * @param eta name of the column containing the pseudorapidity of an electron * @param sf_file path to the file containing the electron scale factors * @param sf_name name of the electron scale factor correction, this parameter * defines what is corrected ID, Iso or Trigger, e.g. "ID90_pt_bins_inc_eta" - * @param correction_type type of the correction, there are two options: `emb` + * @param correction_type type of the correction, there are two options: `emb` * for embedding and `mc` for simulation - * @param extrapolation_factor factor that is used to introduce percent type + * @param extrapolation_factor factor that is used to introduce percent type * variations of the scale factor, default value is `1.0` * * @return a new dataframe containing the new column @@ -326,10 +327,9 @@ PtCorrection(ROOT::RDF::RNode df, ROOT::RDF::RNode Scalefactor(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &eta, - const std::string &sf_file, const std::string &sf_name, - const std::string correction_type, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &sf_file, + const std::string &sf_name, const std::string correction_type, const float &extrapolation_factor = 1.0) { Logger::get("embedding::electron::Scalefactor") @@ -338,7 +338,7 @@ Scalefactor(ROOT::RDF::RNode df, auto df1 = df.Define( outputname, [evaluator, correction_type, extrapolation_factor](const float &pt, - const float &eta) { + const float &eta) { Logger::get("embedding::electron::Scalefactor") ->debug(" pt {}, eta {}, correction_type {}, extrapolation " "factor {}", @@ -379,12 +379,13 @@ PtCorrection_byValue(ROOT::RDF::RNode df, const std::string &outputname, const float &sf_dm10, const float &sf_dm11) { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); - auto correction_lambda = [sf_dm0, sf_dm1, sf_dm10, - sf_dm11](const ROOT::RVec &pts, - const ROOT::RVec &decay_modes_v12) { + auto correction_lambda = [sf_dm0, sf_dm1, sf_dm10, sf_dm11]( + const ROOT::RVec &pts, + const ROOT::RVec &decay_modes_v12) { auto decay_modes = static_cast>(decay_modes_v12); ROOT::RVec corrected_pts(pts.size()); for (int i = 0; i < pts.size(); i++) { @@ -405,23 +406,24 @@ PtCorrection_byValue(ROOT::RDF::RNode df, const std::string &outputname, } return corrected_pts; }; - auto df2 = df1.Define(outputname, correction_lambda, {pt, decay_mode_column}); + auto df2 = + df1.Define(outputname, correction_lambda, {pt, decay_mode_column}); return df2; } namespace scalefactor { /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against jets (`vsJet`) for embedding samples. The scale factors are loaded from - * a correctionlib file using a specified scale factor name and variation. The - * variation and the scale factor itself is binned in transverse momenta (\f$p_T\f$) - * of hadronic taus for this function. This dependence is usually used in semi-leptonic - * channels (\f$e\tau_h\f$, \f$\mu\tau_h\f$). + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against jets (`vsJet`) for embedding samples. The scale factors are + * loaded from a correctionlib file using a specified scale factor name and + * variation. The variation and the scale factor itself is binned in transverse + * momenta (\f$p_T\f$) of hadronic taus for this function. This dependence is + * usually used in semi-leptonic channels (\f$e\tau_h\f$, \f$\mu\tau_h\f$). * - * Description of the bit map used to define the tau ID against jets working points of the - * DeepTau v2.1 tagger. - * vsJets | Value | Bit (value used in the config) + * Description of the bit map used to define the tau ID against jets working + * points of the DeepTau v2.1 tagger. vsJets | + * Value | Bit (value used in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VVVLoose | 1 | 1 @@ -436,29 +438,31 @@ namespace scalefactor { * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsJets ID scale factor + * @param outputname name of the output column containing the vsJets ID scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsJet ID correction * @param selected_dms list of allowed decay modes for which a scale factor * should be calculated * @param wp working point of the vsJet ID * @param vsele_wp working point of the vsEle ID - * @param sf_dependence variable dependence of the scale factor, options are "pt" or "dm" - * @param variation_pt20to25 name of the scale factor variation for \f$20 \leq p_T <25\f$ GeV, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_pt25to30 name of the scale factor variation for \f$25 \leq p_T <30\f$ GeV, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_pt30to35 name of the scale factor variation for \f$30 \leq p_T <35\f$ GeV, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_pt35to40 name of the scale factor variation for \f$35 \leq p_T <40\f$ GeV, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_pt40toInf name of the scale factor variation for \f$40 \leq p_T < \infty \f$ GeV, "nom" for nominal - * and "up"/"down" the up/down variation + * @param sf_dependence variable dependence of the scale factor, options are + * "pt" or "dm" + * @param variation_pt20to25 name of the scale factor variation for \f$20 \leq + * p_T <25\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt25to30 name of the scale factor variation for \f$25 \leq + * p_T <30\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt30to35 name of the scale factor variation for \f$30 \leq + * p_T <35\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt35to40 name of the scale factor variation for \f$35 \leq + * p_T <40\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt40toInf name of the scale factor variation for \f$40 \leq + * p_T < \infty \f$ GeV, "nom" for nominal and "up"/"down" the up/down variation * * @return a new dataframe containing the new column * @@ -468,37 +472,33 @@ namespace scalefactor { ROOT::RDF::RNode Id_vsJet_lt(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::vector &selected_dms, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::vector &selected_dms, const std::string &wp, + const std::string &vsele_wp, const std::string &sf_dependence, const std::string &variation_pt20to25, const std::string &variation_pt25to30, const std::string &variation_pt30to35, const std::string &variation_pt35to40, const std::string &variation_pt40toInf) { - + const std::map variations = { - {20.0f, variation_pt20to25}, - {25.0f, variation_pt25to30}, - {30.0f, variation_pt30to35}, - {35.0f, variation_pt35to40}, - {40.0f, variation_pt40toInf}, - {100000.0f, variation_pt40toInf}, + {20.0f, variation_pt20to25}, {25.0f, variation_pt25to30}, + {30.0f, variation_pt30to35}, {35.0f, variation_pt35to40}, + {40.0f, variation_pt40toInf}, {100000.0f, variation_pt40toInf}, }; Logger::get("embedding::tau::scalefactor::Id_vsJet_lt") ->debug("Setting up function for tau id vsJet sf"); - Logger::get("embedding::tau::scalefactor::Id_vsJet_lt")->debug("ID - Name {}", sf_name); + Logger::get("embedding::tau::scalefactor::Id_vsJet_lt") + ->debug("ID - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto sf_calculator = [evaluator, wp, vsele_wp, variations, - sf_dependence, selected_dms, - sf_name](const float &pt, const int &decay_mode, - const int &gen_match) { - Logger::get("embedding::tau::scalefactor::Id_vsJet_lt")->debug("ID - decayMode {}", decay_mode); + auto sf_calculator = [evaluator, wp, vsele_wp, variations, sf_dependence, + selected_dms, + sf_name](const float &pt, const int &decay_mode, + const int &gen_match) { + Logger::get("embedding::tau::scalefactor::Id_vsJet_lt") + ->debug("ID - decayMode {}", decay_mode); // only calculate SFs for allowed tau decay modes (also excludes default // values due to tau energy correction shifts below good tau pt // selection) @@ -506,23 +506,27 @@ Id_vsJet_lt(ROOT::RDF::RNode df, if (std::find(selected_dms.begin(), selected_dms.end(), decay_mode) != selected_dms.end()) { auto it = variations.upper_bound(pt); - if (it != variations.begin()){ + if (it != variations.begin()) { it = std::prev(it); std::string variation = it->second; Logger::get("embedding::tau::scalefactor::Id_vsJet_lt") - ->debug("ID {} - pt {}, decay_mode {}, gen_match {}, wp {}, " + ->debug( + "ID {} - pt {}, decay_mode {}, gen_match {}, wp {}, " "vsele_wp {}, variation {}, sf_dependence {}", sf_name, pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence); - sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence}); + sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, + vsele_wp, variation, sf_dependence}); } else { sf = 1.; } } - Logger::get("embedding::tau::scalefactor::Id_vsJet_lt")->debug("Scale Factor {}", sf); + Logger::get("embedding::tau::scalefactor::Id_vsJet_lt") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); + auto df1 = + df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); return df1; } } // end namespace scalefactor diff --git a/src/event.cxx b/src/event.cxx index 5d3a306d..820fd676 100644 --- a/src/event.cxx +++ b/src/event.cxx @@ -14,45 +14,43 @@ namespace quantity { /** * @brief This function defines a new column in the dataframe with seeds for a * random number generator for each event. - * + * * The seed value for each event is calculated by concatenating event index * variables and a seed value to `{seed}_{lumi}_{run}_{event}`. From that, a * SHA256 hash is calculated. The first four bytes of the hash are then used * to create a 32-bit unsigned integer, which serves as the event seed. - * + * * @param df input dataframe * @param outputname name of the new column containing the generated event seeds * @param lumi name of the column containing the luminosity block number * @param run name of the column containing the run number * @param event name of the column containing the event number - * @param master_seed master seed value to be added to the hash used for event seed - * generation + * @param master_seed master seed value to be added to the hash used for event + * seed generation * * @return a dataframe with the new column */ -ROOT::RDF::RNode -GenerateSeed( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lumi, - const std::string &run, - const std::string &event, - const UInt_t &master_seed = 42 -) { - - auto generate_seed = [master_seed] ( - const unsigned int &lumi, - const unsigned int &run, - const unsigned long long &event - ) { +ROOT::RDF::RNode GenerateSeed(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &lumi, const std::string &run, + const std::string &event, + const UInt_t &master_seed = 42) { + + auto generate_seed = [master_seed](const unsigned int &lumi, + const unsigned int &run, + const unsigned long long &event) { // string for setting the seed value - const std::string seed_string = std::to_string(master_seed) + "_" + std::to_string(lumi) + "_" + std::to_string(run) + "_" + std::to_string(event); + const std::string seed_string = + std::to_string(master_seed) + "_" + std::to_string(lumi) + "_" + + std::to_string(run) + "_" + std::to_string(event); // create a SHA256 has from the seed string unsigned char hash[SHA256_DIGEST_LENGTH]; - SHA256(reinterpret_cast(seed_string.c_str()), seed_string.size(), hash); + SHA256(reinterpret_cast(seed_string.c_str()), + seed_string.size(), hash); - // use the first for bits of the hash to create a 32-bit unsigned integer as seed + // use the first for bits of the hash to create a 32-bit unsigned + // integer as seed unsigned int event_seed = 0; for (int i = 0; i < 4; ++i) { event_seed = (event_seed << 8) | hash[i]; @@ -61,11 +59,7 @@ GenerateSeed( return event_seed; }; - return df.Define( - outputname, - generate_seed, - {lumi, run, event} - ); + return df.Define(outputname, generate_seed, {lumi, run, event}); } } // end namespace quantity diff --git a/src/fatjets.cxx b/src/fatjets.cxx index 58dc5fbf..6faff49f 100644 --- a/src/fatjets.cxx +++ b/src/fatjets.cxx @@ -16,101 +16,101 @@ namespace fatjet { namespace quantity { /** - * @brief This function calculates a discriminator score from two ParticleNet - * tagger outputs (a signal X and the QCD background). The signal can e.g. be - * \f$X\rightarrow bb\f$ or \f$X\rightarrow cc\f$ etc. - * - * The score is computed using the formula: + * @brief This function calculates a discriminator score from two ParticleNet + * tagger outputs (a signal X and the QCD background). The signal can e.g. be + * \f$X\rightarrow bb\f$ or \f$X\rightarrow cc\f$ etc. + * + * The score is computed using the formula: * \f[ * Score = \frac{P(X)}{P(X) + P(QCD)} * \f] * - * @note This function is mainly needed when working with `nanoAODv9`, in newer + * @note This function is mainly needed when working with `nanoAODv9`, in newer * versions this ratio is already included as a branch. * * @param df input dataframe * @param outputname name of the new column containing the XvsQCD score - * @param pNet_X_decay name of the column containing the ParticleNet score for + * @param pNet_X_decay name of the column containing the ParticleNet score for * the signal process (\f$X\rightarrow ...\f$) - * @param pNet_QCD name of the column containing the ParticleNet score for the + * @param pNet_QCD name of the column containing the ParticleNet score for the * QCD background - * @param fatjet_collection name of the column containing a collection (vector) + * @param fatjet_collection name of the column containing a collection (vector) * of good fatjet indices - * @param position position of the fatjet in the collection (vector) that should + * @param position position of the fatjet in the collection (vector) that should * be used for the score calculation * * @return a new dataframe containing the new column */ ROOT::RDF::RNode ParticleNet_XvsQCD(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &pNet_X_decay, const std::string &pNet_QCD, - const std::string &fatjet_collection, const int &position) { + const std::string &pNet_X_decay, const std::string &pNet_QCD, + const std::string &fatjet_collection, const int &position) { return df.Define(outputname, [position](const ROOT::RVec &X_tagger, const ROOT::RVec &QCD_tagger, const ROOT::RVec &fatjets) { - float X_decay = default_float; - float QCD = default_float; - float X_vs_QCD = default_float; - if (position >= 0) { - const int index = fatjets.at(position); - if (index >= 0) { - X_decay = X_tagger.at(index); - QCD = QCD_tagger.at(index); - X_vs_QCD = X_decay / (X_decay + QCD); - } - } - return X_vs_QCD; + float X_decay = default_float; + float QCD = default_float; + float X_vs_QCD = default_float; + if (position >= 0) { + const int index = fatjets.at(position); + if (index >= 0) { + X_decay = X_tagger.at(index); + QCD = QCD_tagger.at(index); + X_vs_QCD = X_decay / (X_decay + QCD); + } + } + return X_vs_QCD; }, {pNet_X_decay, pNet_QCD, fatjet_collection}); } /** - * @brief This function calculates the ratio of two N-subjettiness variables + * @brief This function calculates the ratio of two N-subjettiness variables * of one fatjet, typically used for discriminating jet substructure: * \f[ * \tau_{ratio} = \frac{\tau_N}{\tau_{N-1}} * \f] - * For example, \f$\tau_{21} = \tau_2 / \tau_1\f$ for 2-prong vs. 1-prong decay - * identification. The resulting ratio is always between 0 and 1. If it is close - * to 0, the jet is more likely to be a N-prong jet, while a value close to 1 + * For example, \f$\tau_{21} = \tau_2 / \tau_1\f$ for 2-prong vs. 1-prong decay + * identification. The resulting ratio is always between 0 and 1. If it is close + * to 0, the jet is more likely to be a N-prong jet, while a value close to 1 * indicates a (N-1)-prong jet. * * @param df input dataframe * @param outputname name of the new column containing the N-subjettiness ratio - * @param tau_N name of the column containing the N-subjettiness variable for + * @param tau_N name of the column containing the N-subjettiness variable for * the numerator with number `N` - * @param tau_Nm1 name of the column containing the N-subjettiness variable for + * @param tau_Nm1 name of the column containing the N-subjettiness variable for * the denominator with number `N-1` - * @param fatjet_collection name of the column containing a collection (vector) + * @param fatjet_collection name of the column containing a collection (vector) * of good fatjet indices - * @param position position of the fatjet in the collection (vector) that should + * @param position position of the fatjet in the collection (vector) that should * be used for the ratio calculation * * @return a new dataframe containing the new column */ ROOT::RDF::RNode NsubjettinessRatio(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &tau_N, const std::string &tau_Nm1, - const std::string &fatjet_collection, const int &position) { + const std::string &tau_N, const std::string &tau_Nm1, + const std::string &fatjet_collection, const int &position) { return df.Define(outputname, - [position](const ROOT::RVec &tau_N, - const ROOT::RVec &tau_Nm1, - const ROOT::RVec &fatjets) { - float nsubjet_N = default_float; - float nsubjet_Nm1 = default_float; - float ratio = default_float; - if (position >= 0) { - const int index = fatjets.at(position); - if (index >= 0) { - nsubjet_N = tau_N.at(index); - nsubjet_Nm1 = tau_Nm1.at(index); - ratio = nsubjet_N / nsubjet_Nm1; - } - } - return ratio; - }, - {tau_N, tau_Nm1, fatjet_collection}); + [position](const ROOT::RVec &tau_N, + const ROOT::RVec &tau_Nm1, + const ROOT::RVec &fatjets) { + float nsubjet_N = default_float; + float nsubjet_Nm1 = default_float; + float ratio = default_float; + if (position >= 0) { + const int index = fatjets.at(position); + if (index >= 0) { + nsubjet_N = tau_N.at(index); + nsubjet_Nm1 = tau_Nm1.at(index); + ratio = nsubjet_N / nsubjet_Nm1; + } + } + return ratio; + }, + {tau_N, tau_Nm1, fatjet_collection}); } } // end namespace quantity } // end namespace fatjet diff --git a/src/genparticles.cxx b/src/genparticles.cxx index 7b7f7af6..2e4c067a 100644 --- a/src/genparticles.cxx +++ b/src/genparticles.cxx @@ -1,9 +1,9 @@ #ifndef GUARD_GENPARTICLES_H #define GUARD_GENPARTICLES_H +#include "../include/defaults.hxx" #include "../include/utility/Logger.hxx" #include "../include/utility/utility.hxx" -#include "../include/defaults.hxx" #include "ROOT/RDataFrame.hxx" #include "ROOT/RVec.hxx" #include "bitset" @@ -31,19 +31,21 @@ namespace genparticles { /** * @brief This function reconstructs the Lorentz vector of a generator-level * boson (e.g., W, Z, H). The reconstruction is performed by looping over all - * genparticles in an event and selecting final-state leptons that originate from - * the hard process. + * genparticles in an event and selecting final-state leptons that originate + * from the hard process. * * The particle selection criteria are: * 1. The particle is a lepton (PDG ID 11-16) with status=1 (stable) and the * 'fromHardProcessFinalState' (bit 8) status flag * OR - * 2. The particle has the `isDirectHardProcessTauDecayProduct` (bit 10) status flag + * 2. The particle has the `isDirectHardProcessTauDecayProduct` (bit 10) status + * flag * - * For real data (when `is_data` is true), a default Lorentz vector is returned, as - * no generator-level information is available. + * For real data (when `is_data` is true), a default Lorentz vector is returned, + * as no generator-level information is available. * - * The meaning of the genparticle status flag codes is listed in the table below. + * The meaning of the genparticle status flag codes is listed in the table + * below. * * Meaning | Value | Bit (value used in the config) * ------------------------------------|-------|------- @@ -64,7 +66,8 @@ namespace genparticles { * isLastCopyBeforeFSR | 16384 | 14 * * @param df input dataframe - * @param outputname name of the new column containing the reconstructed gen. boson + * @param outputname name of the new column containing the reconstructed gen. + * boson * @param genparticles_pt name of the column containing the \f$p_T\f$ of the * genparticles * @param genparticles_eta name of the column containing the \f$\eta\f$ of the @@ -79,32 +82,31 @@ namespace genparticles { * genparticles * @param genparticles_status_flags name of the column containing the status * flags of the genparticles, e.g. isPrompt, isHardProcess, isLastCopy, ... - * @param is_data boolean flag to indicate if real data (true) or simulation (false) - * is processed + * @param is_data boolean flag to indicate if real data (true) or simulation + * (false) is processed * * @return a new dataframe containing the gen. boson Lorentz vector */ -ROOT::RDF::RNode GetBoson( - ROOT::RDF::RNode df, const std::string outputname, - const std::string &genparticles_pt, const std::string &genparticles_eta, - const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &genparticles_pdg_id, const std::string &genparticles_status, - const std::string &genparticles_status_flags, bool is_data) { +ROOT::RDF::RNode GetBoson(ROOT::RDF::RNode df, const std::string outputname, + const std::string &genparticles_pt, + const std::string &genparticles_eta, + const std::string &genparticles_phi, + const std::string &genparticles_mass, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status, + const std::string &genparticles_status_flags, + bool is_data) { auto calculateGenBosonVector = - [](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses, - const ROOT::RVec &pdg_ids, - const ROOT::RVec &status, + [](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, const ROOT::RVec &masses, + const ROOT::RVec &pdg_ids, const ROOT::RVec &status, const ROOT::RVec &status_flags_v12) { auto status_flags = static_cast>(status_flags_v12); ROOT::Math::PtEtaPhiMVector genBoson; ROOT::Math::PtEtaPhiMVector genparticle; // now loop though all genparticles in the event - for (std::size_t index = 0; index < pdg_ids.size(); - ++index) { + for (std::size_t index = 0; index < pdg_ids.size(); ++index) { // consider a genparticle if // 1. if it is: // * a lepton @@ -112,16 +114,21 @@ ROOT::RDF::RNode GetBoson( // * status 1 // or // 2. if it is - // * isDirectHardProcessTauDecayProduct --> bit 10 (status flag) + // * isDirectHardProcessTauDecayProduct --> bit 10 (status + // flag) Logger::get("genparticles::GetBoson") ->debug("Checking particle {} ", pdg_ids.at(index)); - if ((abs(pdg_ids.at(index)) >= 11 && abs(pdg_ids.at(index)) <= 16 && - (IntBits(status_flags.at(index)).test(8)) && status.at(index) == 1) || + if ((abs(pdg_ids.at(index)) >= 11 && + abs(pdg_ids.at(index)) <= 16 && + (IntBits(status_flags.at(index)).test(8)) && + status.at(index) == 1) || (IntBits(status_flags.at(index)).test(10))) { Logger::get("genparticles::GetBoson") - ->debug("Adding {} to gen boson vector", pdg_ids.at(index)); + ->debug("Adding {} to gen boson vector", + pdg_ids.at(index)); genparticle = ROOT::Math::PtEtaPhiMVector( - pts.at(index), etas.at(index), phis.at(index), masses.at(index)); + pts.at(index), etas.at(index), phis.at(index), + masses.at(index)); genBoson = genBoson + genparticle; } } @@ -129,18 +136,19 @@ ROOT::RDF::RNode GetBoson( }; if (!is_data) { - // In nanoAODv12 the type of genparticle status flags was changed to UShort_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); + // In nanoAODv12 the type of genparticle status flags was changed to + // UShort_t For v9 compatibility a type casting is applied + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); return df1.Define(outputname, calculateGenBosonVector, - {genparticles_pt, genparticles_eta, genparticles_phi, - genparticles_mass, genparticles_pdg_id, genparticles_status, - genparticles_status_flags_column}); + {genparticles_pt, genparticles_eta, genparticles_phi, + genparticles_mass, genparticles_pdg_id, + genparticles_status, + genparticles_status_flags_column}); } else { - return df.Define(outputname, []() { - return default_lorentzvector; - }); + return df.Define(outputname, []() { return default_lorentzvector; }); } } @@ -148,23 +156,25 @@ ROOT::RDF::RNode GetBoson( * @brief This function reconstructs the Lorentz vector of a generator-level * boson (e.g., W, Z, H), explicitly excluding neutrinos to represent only the * visible energy and momentum. The reconstruction is performed by looping over - * all genparticles in an event and selecting final-state leptons (except neutrinos) - * that originate from the hard process. + * all genparticles in an event and selecting final-state leptons (except + * neutrinos) that originate from the hard process. * * The particle selection criteria are: * 1. The particle is a lepton (PDG ID 11-16) with status=1 (stable) and the * 'fromHardProcessFinalState' (bit 8) status flag * OR - * 2. The particle has the `isDirectHardProcessTauDecayProduct` (bit 10) status flag + * 2. The particle has the `isDirectHardProcessTauDecayProduct` (bit 10) status + * flag * - * Further, particles identified as neutrinos (PDG IDs 12, 14, 16) that pass these - * initial checks are then excluded from the final four-vector sum. + * Further, particles identified as neutrinos (PDG IDs 12, 14, 16) that pass + * these initial checks are then excluded from the final four-vector sum. * - * For real data (when `is_data` is true), a default Lorentz vector is returned, as - * no generator-level information is available. + * For real data (when `is_data` is true), a default Lorentz vector is returned, + * as no generator-level information is available. * * @param df input dataframe - * @param outputname name of the new column containing the reconstructed gen. boson + * @param outputname name of the new column containing the reconstructed gen. + * boson * @param genparticles_pt name of the column containing the \f$p_T\f$ of the * genparticles * @param genparticles_eta name of the column containing the \f$\eta\f$ of the @@ -179,8 +189,8 @@ ROOT::RDF::RNode GetBoson( * genparticles * @param genparticles_status_flags name of the column containing the status * flags of the genparticles, e.g. isPrompt, isHardProcess, isLastCopy, ... - * @param is_data boolean flag to indicate if real data (true) or simulation (false) - * is processed + * @param is_data boolean flag to indicate if real data (true) or simulation + * (false) is processed * * @return a new dataframe containing the visible gen. boson Lorentz vector */ @@ -188,23 +198,20 @@ ROOT::RDF::RNode GetVisibleBoson( ROOT::RDF::RNode df, const std::string outputname, const std::string &genparticles_pt, const std::string &genparticles_eta, const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &genparticles_pdg_id, const std::string &genparticles_status, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status, const std::string &genparticles_status_flags, bool is_data) { auto calculateGenVisBosonVector = - [](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses, - const ROOT::RVec &pdg_ids, - const ROOT::RVec &status, + [](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, const ROOT::RVec &masses, + const ROOT::RVec &pdg_ids, const ROOT::RVec &status, const ROOT::RVec &status_flags_v12) { auto status_flags = static_cast>(status_flags_v12); ROOT::Math::PtEtaPhiMVector genVisBoson; ROOT::Math::PtEtaPhiMVector genparticle; // now loop though all genparticles in the event - for (std::size_t index = 0; index < pdg_ids.size(); - ++index) { + for (std::size_t index = 0; index < pdg_ids.size(); ++index) { // consider a genparticle if // 1. if it is: // * a lepton @@ -212,21 +219,26 @@ ROOT::RDF::RNode GetVisibleBoson( // * status 1 // or // 2. if it is - // * isDirectHardProcessTauDecayProduct --> bit 10 (status flag) + // * isDirectHardProcessTauDecayProduct --> bit 10 (status + // flag) Logger::get("genparticles::GetVisibleBoson") ->debug("Checking particle {} ", pdg_ids.at(index)); - if ((abs(pdg_ids.at(index)) >= 11 && abs(pdg_ids.at(index)) <= 16 && - (IntBits(status_flags.at(index)).test(8)) && status.at(index) == 1) || + if ((abs(pdg_ids.at(index)) >= 11 && + abs(pdg_ids.at(index)) <= 16 && + (IntBits(status_flags.at(index)).test(8)) && + status.at(index) == 1) || (IntBits(status_flags.at(index)).test(10))) { - // if the genparticle is not a neutrino, we add it to the visible - // gen boson vector + // if the genparticle is not a neutrino, we add it to the + // visible gen boson vector if (abs(pdg_ids.at(index)) != 12 && abs(pdg_ids.at(index)) != 14 && abs(pdg_ids.at(index)) != 16) { Logger::get("genparticles::GetVisibleBoson") - ->debug("Adding {} to visible gen boson vector", pdg_ids.at(index)); + ->debug("Adding {} to visible gen boson vector", + pdg_ids.at(index)); genparticle = ROOT::Math::PtEtaPhiMVector( - pts.at(index), etas.at(index), phis.at(index), masses.at(index)); + pts.at(index), etas.at(index), phis.at(index), + masses.at(index)); genVisBoson = genVisBoson + genparticle; } } @@ -235,41 +247,42 @@ ROOT::RDF::RNode GetVisibleBoson( }; if (!is_data) { - // In nanoAODv12 the type of genparticle status flags was changed to UShort_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); + // In nanoAODv12 the type of genparticle status flags was changed to + // UShort_t. For v9 compatibility a type casting is applied. + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); return df1.Define(outputname, calculateGenVisBosonVector, - {genparticles_pt, genparticles_eta, genparticles_phi, - genparticles_mass, genparticles_pdg_id, genparticles_status, - genparticles_status_flags_column}); + {genparticles_pt, genparticles_eta, genparticles_phi, + genparticles_mass, genparticles_pdg_id, + genparticles_status, + genparticles_status_flags_column}); } else { - return df.Define(outputname, []() { - return default_lorentzvector; - }); + return df.Define(outputname, []() { return default_lorentzvector; }); } } namespace tau { /** - * @brief This function finds all hadronic generator-level taus needed for the + * @brief This function finds all hadronic generator-level taus needed for the * matching to the reconstructed hadronic taus, based on the implementation from * https://github.com/KIT-CMS/Artus/blob/dictchanges/KappaAnalysis/src/Utility/GeneratorInfo.cc * * The procedure is go trough all genparticles and check, if a genparticle, * that is prompt, without any leptonic daughters can be found. If this * genparticle has a neutrino as daughter, this genparticle is indentified as - * a hadronic generator-level tau (GenTau). + * a hadronic generator-level tau (GenTau). * * @param df input dataframe - * @param outputname name of the output column containing the hadronic tau + * @param outputname name of the output column containing the hadronic tau * indices vector * @param genparticles_pdg_id name of the column containing the PDG IDs of the * genparticles - * @param genparticles_status_flags name of the column containing the status + * @param genparticles_status_flags name of the column containing the status * flags of the genparticles, e.g. isPrompt, isHardProcess, isLastCopy, ... - * @param genparticles_mother_index name of the column containing the mother + * @param genparticles_mother_index name of the column containing the mother * particle indices of the genparticles * * @return a new dataframe with the new column @@ -279,12 +292,17 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, const std::string &genparticles_pdg_id, const std::string &genparticles_status_flags, const std::string &genparticles_mother_index) { - // In nanoAODv12 the type of genparticle status flags / mother index were changed to UShort_t / Short_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); - auto [df2, genparticles_mother_index_column] = utility::Cast, ROOT::RVec>( - df1, genparticles_mother_index+"_v12", "ROOT::VecOps::RVec", genparticles_mother_index); + // In nanoAODv12 the type of genparticle status flags / mother index were + // changed to UShort_t / Short_t. For v9 compatibility a type casting is + // applied. + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); + auto [df2, genparticles_mother_index_column] = + utility::Cast, ROOT::RVec>( + df1, genparticles_mother_index + "_v12", + "ROOT::VecOps::RVec", genparticles_mother_index); auto gentaus = [](const ROOT::RVec &pdg_ids, const ROOT::RVec &status_flags_v12, @@ -343,8 +361,8 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, hasLeptonDaughter = true; } } - // in this case, the tau decayed leptonically or is not - // in its final state, therefore, it is not the correct + // in this case, the tau decayed leptonically or is not + // in its final state, therefore, it is not the correct // tau, continue if (hasTauDaughter || hasLeptonDaughter) { continue; @@ -357,7 +375,8 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, std::abs(pdg_ids.at(daughters.at(j))); if (daughter_pdgid == 12 || daughter_pdgid == 14 || daughter_pdgid == 16) { - Logger::get("genparticles::tau::HadronicGenTaus") + Logger::get( + "genparticles::tau::HadronicGenTaus") ->debug("gentau found: {}", i); hadGenTaus.push_back(i); } @@ -367,25 +386,26 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, } } Logger::get("genparticles::tau::HadronicGenTaus") - ->debug("found {} hadronic GenTaus", - hadGenTaus.size()); + ->debug("found {} hadronic GenTaus", hadGenTaus.size()); for (int i = 0; i < hadGenTaus.size(); i++) { Logger::get("genparticles::tau::HadronicGenTaus") ->debug("hadronicGenTaus {} : {}", i, hadGenTaus.at(i)); } return hadGenTaus; }; - auto df3 = df2.Define( - outputname, gentaus, - {genparticles_pdg_id, genparticles_status_flags_column, genparticles_mother_index_column}); + auto df3 = + df2.Define(outputname, gentaus, + {genparticles_pdg_id, genparticles_status_flags_column, + genparticles_mother_index_column}); return df3; } /** - * @brief This function determines the true origin of a reconstructed hadronic tau - * by matching it to generator-level particles. The implementation is based on + * @brief This function determines the true origin of a reconstructed hadronic + * tau by matching it to generator-level particles. The implementation is based + * on * https://github.com/KIT-CMS/Artus/blob/dictchanges/KappaAnalysis/src/Utility/GeneratorInfo.cc - * + * * The matching is represented by integer flags: * Decaytype | Value * ----------------------|------- @@ -397,31 +417,35 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, * IS_FAKE (not matched) | 6 * * The matching logic is as follows: - * 1. For each reconstructed tau, first, the closest "prompt" or "from tau decay" - * generator-level electron or muon with \f$p_T\f$ > 8 GeV is found. The distance + * 1. For each reconstructed tau, first, the closest "prompt" or "from tau + * decay" generator-level electron or muon with \f$p_T\f$ > 8 GeV is found. The + * distance * (\f$\Delta R\f$) to this lepton is saved. - * 2. Next, an iteration is done through pre-identified generator-level hadronic taus. - * If a gen. tau with \f$p_T\f$ > 15 GeV is found within a cone of \f$\Delta R\f$ < 0.2 - * of the reco. tau, and it is closer than the closest electron/muon found in step 1, - * the match is classified as `IS_TAU_HAD_DECAY` (value: 5). - * 3. If no such hadronic tau is found, it re-evaluates the closest electron/muon from - * step 1. If this lepton is within \f$\Delta R\f$ < 0.2 of the reco. tau, the match is - * classified based on the lepton's identity and origin: + * 2. Next, an iteration is done through pre-identified generator-level hadronic + * taus. If a gen. tau with \f$p_T\f$ > 15 GeV is found within a cone of + * \f$\Delta R\f$ < 0.2 of the reco. tau, and it is closer than the closest + * electron/muon found in step 1, the match is classified as `IS_TAU_HAD_DECAY` + * (value: 5). + * 3. If no such hadronic tau is found, it re-evaluates the closest + * electron/muon from step 1. If this lepton is within \f$\Delta R\f$ < 0.2 of + * the reco. tau, the match is classified based on the lepton's identity and + * origin: * - Prompt electron (other): `IS_ELE_PROMPT` (value: 1) * - Prompt muon (other): `IS_MUON_PROMPT` (value: 2) * - Electron from a tau decay: `IS_ELE_FROM_TAU` (value: 3) * - Muon from a tau decay: `IS_MUON_FROM_TAU` (value: 4) - * 4. If nothing of the above is matched, the reco. tau is classified as a `IS_FAKE` - * (value: 6). + * 4. If nothing of the above is matched, the reco. tau is classified as a + * `IS_FAKE` (value: 6). * * @param df input dataframe - * @param outputname name of the output column containing the gen. matching value - * @param hadronic_gen_taus name of the column containing the hadronic gen. tau indices - * found with `genparticles::tau::HadronicGenTaus` + * @param outputname name of the output column containing the gen. matching + * value + * @param hadronic_gen_taus name of the column containing the hadronic gen. tau + * indices found with `genparticles::tau::HadronicGenTaus` * @param genparticles_pdg_id name of the column containing the PDG IDs of the * genparticles - * @param genparticles_status_flags name of the column containing the status - * flags of the genparticles, e.g. isPrompt, isHardProcess, + * @param genparticles_status_flags name of the column containing the status + * flags of the genparticles, e.g. isPrompt, isHardProcess, * isLastCopy, ... * @param genparticles_pt name of the column containing the \f$p_T\f$ of the * genparticles @@ -431,30 +455,35 @@ ROOT::RDF::RNode HadronicGenTaus(ROOT::RDF::RNode df, * genparticles * @param genparticles_mass name of the column containing the mass of the * genparticles - * @param reco_had_tau name of the column containing the Lorentz vector of the + * @param reco_had_tau name of the column containing the Lorentz vector of the * reconstructed hadronic tau lepton * * @return a new dataframe with the new column */ -ROOT::RDF::RNode GenMatching( - ROOT::RDF::RNode df, const std::string &outputname, - const std::string &hadronic_gen_taus, const std::string &genparticles_pdg_id, - const std::string &genparticles_status_flags, const std::string &genparticles_pt, - const std::string &genparticles_eta, const std::string &genparticles_phi, - const std::string &genparticles_mass, const std::string &reco_had_tau) { - // In nanoAODv12 the type of genparticle status flags was changed to UShort_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); +ROOT::RDF::RNode GenMatching(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &hadronic_gen_taus, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status_flags, + const std::string &genparticles_pt, + const std::string &genparticles_eta, + const std::string &genparticles_phi, + const std::string &genparticles_mass, + const std::string &reco_had_tau) { + // In nanoAODv12 the type of genparticle status flags was changed to + // UShort_t. For v9 compatibility a type casting is applied. + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); auto match_tau = [](const std::vector &had_gen_taus, - const ROOT::RVec &pdg_ids, - const ROOT::RVec &status_flags_v12, - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses, - const ROOT::Math::PtEtaPhiMVector &reco_had_tau) { + const ROOT::RVec &pdg_ids, + const ROOT::RVec &status_flags_v12, + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &masses, + const ROOT::Math::PtEtaPhiMVector &reco_had_tau) { auto status_flags = static_cast>(status_flags_v12); // find closest lepton fulfilling the requirements float min_delta_r = 9999; @@ -473,14 +502,14 @@ ROOT::RDF::RNode GenMatching( bool statusbit = (IntBits(status_flags.at(i)).test(0) || IntBits(status_flags.at(i)).test(5)); if ((pdgid == 11 || pdgid == 13) && pts.at(i) > 8 && statusbit) { - ROOT::Math::PtEtaPhiMVector probe_gen_tau(pts.at(i), etas.at(i), - phis.at(i), masses.at(i)); + ROOT::Math::PtEtaPhiMVector probe_gen_tau( + pts.at(i), etas.at(i), phis.at(i), masses.at(i)); float delta_r = ROOT::Math::VectorUtil::DeltaR(probe_gen_tau, reco_had_tau); if (delta_r < min_delta_r) { Logger::get("genparticles::tau::GenMatching") - ->debug("pdg_ids {}, status_flags {}", - pdg_ids.at(i), status_flags.at(i)); + ->debug("pdg_ids {}, status_flags {}", pdg_ids.at(i), + status_flags.at(i)); closest_genparticle_index = i; min_delta_r = delta_r; } @@ -495,8 +524,8 @@ ROOT::RDF::RNode GenMatching( // check if the gen_tau is closer to the lepton than the // closest lepton genparticle ROOT::Math::PtEtaPhiMVector probe_gen_tau( - pts.at(gen_tau), etas.at(gen_tau), - phis.at(gen_tau), masses.at(gen_tau)); + pts.at(gen_tau), etas.at(gen_tau), phis.at(gen_tau), + masses.at(gen_tau)); float gen_tau_delta_r = ROOT::Math::VectorUtil::DeltaR(probe_gen_tau, reco_had_tau); // the decay is considered a hadronic decay (statusbit 5) if @@ -508,9 +537,9 @@ ROOT::RDF::RNode GenMatching( gen_tau_delta_r < min_delta_r) { // statusbit 5 is hadronic tau decay Logger::get("genparticles::tau::GenMatching") - ->debug( - "found hadronic gen. tau closer than closest lepton: {}", - gen_tau_delta_r); + ->debug("found hadronic gen. tau closer than closest " + "lepton: {}", + gen_tau_delta_r); Logger::get("genparticles::tau::GenMatching") ->debug("IS_TAU_HAD_DECAY"); return (int)MatchingGenTauCode::IS_TAU_HAD_DECAY; @@ -554,19 +583,22 @@ ROOT::RDF::RNode GenMatching( Logger::get("genparticles::tau::GenMatching")->debug("IS_FAKE"); return (int)MatchingGenTauCode::IS_FAKE; }; - auto df2 = df1.Define( - outputname, match_tau, - {hadronic_gen_taus, genparticles_pdg_id, genparticles_status_flags_column, - genparticles_pt, genparticles_eta, genparticles_phi, genparticles_mass, reco_had_tau}); + auto df2 = df1.Define(outputname, match_tau, + {hadronic_gen_taus, genparticles_pdg_id, + genparticles_status_flags_column, genparticles_pt, + genparticles_eta, genparticles_phi, + genparticles_mass, reco_had_tau}); return df2; } /** - * @brief This function determines the true origin of a reconstructed hadronic tau - * by matching it to generator-level particles. The implementation is based on + * @brief This function determines the true origin of a reconstructed hadronic + * tau by matching it to generator-level particles. The implementation is based + * on * https://github.com/KIT-CMS/Artus/blob/dictchanges/KappaAnalysis/src/Utility/GeneratorInfo.cc - * - * @note This function additionally matches if the prompt electron/muon decayed from a W boson. + * + * @note This function additionally matches if the prompt electron/muon decayed + * from a W boson. * * The matching is represented by integer flags: * Decaytype | Value @@ -581,35 +613,39 @@ ROOT::RDF::RNode GenMatching( * IS_MUON_PROMPT_FROM_W | 8 * * The matching logic is as follows: - * 1. For each reconstructed tau, first, the closest "prompt" or "from tau decay" - * generator-level electron or muon with \f$p_T\f$ > 8 GeV is found. The distance + * 1. For each reconstructed tau, first, the closest "prompt" or "from tau + * decay" generator-level electron or muon with \f$p_T\f$ > 8 GeV is found. The + * distance * (\f$\Delta R\f$) to this lepton is saved. - * 2. Next, an iteration is done through pre-identified generator-level hadronic taus. - * If a gen. tau with \f$p_T\f$ > 15 GeV is found within a cone of \f$\Delta R\f$ < 0.2 - * of the reco. tau, and it is closer than the closest electron/muon found in step 1, - * the match is classified as `IS_TAU_HAD_DECAY` (value: 5). - * 3. If no such hadronic tau is found, it re-evaluates the closest electron/muon from - * step 1. If this lepton is within \f$\Delta R\f$ < 0.2 of the reco. tau, the match is - * classified based on the lepton's identity and origin: + * 2. Next, an iteration is done through pre-identified generator-level hadronic + * taus. If a gen. tau with \f$p_T\f$ > 15 GeV is found within a cone of + * \f$\Delta R\f$ < 0.2 of the reco. tau, and it is closer than the closest + * electron/muon found in step 1, the match is classified as `IS_TAU_HAD_DECAY` + * (value: 5). + * 3. If no such hadronic tau is found, it re-evaluates the closest + * electron/muon from step 1. If this lepton is within \f$\Delta R\f$ < 0.2 of + * the reco. tau, the match is classified based on the lepton's identity and + * origin: * - Prompt electron (from W boson): `IS_ELE_PROMPT_FROM_W` (value: 7) * - Prompt electron (other): `IS_ELE_PROMPT` (value: 1) * - Prompt muon (from W boson): `IS_MUON_PROMPT_FROM_W` (value: 8) * - Prompt muon (other): `IS_MUON_PROMPT` (value: 2) * - Electron from a tau decay: `IS_ELE_FROM_TAU` (value: 3) * - Muon from a tau decay: `IS_MUON_FROM_TAU` (value: 4) - * 4. If nothing of the above is matched, the reco. tau is classified as a `IS_FAKE` - * (value: 6). + * 4. If nothing of the above is matched, the reco. tau is classified as a + * `IS_FAKE` (value: 6). * * @param df input dataframe - * @param outputname name of the output column containing the gen. matching value - * @param hadronic_gen_taus name of the column containing the hadronic gen. tau indices - * found with `genparticles::tau::HadronicGenTaus` + * @param outputname name of the output column containing the gen. matching + * value + * @param hadronic_gen_taus name of the column containing the hadronic gen. tau + * indices found with `genparticles::tau::HadronicGenTaus` * @param genparticles_pdg_id name of the column containing the PDG IDs of the * genparticles - * @param genparticles_status_flags name of the column containing the status - * flags of the genparticles, e.g. isPrompt, isHardProcess, + * @param genparticles_status_flags name of the column containing the status + * flags of the genparticles, e.g. isPrompt, isHardProcess, * isLastCopy, ... - * @param genparticles_mother_index name of the column containing the mother + * @param genparticles_mother_index name of the column containing the mother * particle indices of the genparticles * @param genparticles_pt name of the column containing the \f$p_T\f$ of the * genparticles @@ -619,34 +655,42 @@ ROOT::RDF::RNode GenMatching( * genparticles * @param genparticles_mass name of the column containing the mass of the * genparticles - * @param reco_had_tau name of the column containing the Lorentz vector of the + * @param reco_had_tau name of the column containing the Lorentz vector of the * reconstructed hadronic tau lepton * * @return a new dataframe with the new column */ -ROOT::RDF::RNode GenMatching( - ROOT::RDF::RNode df, const std::string &outputname, - const std::string &hadronic_gen_taus, const std::string &genparticles_pdg_id, - const std::string &genparticles_status_flags, const std::string &genparticles_mother_index, - const std::string &genparticles_pt, const std::string &genparticles_eta, - const std::string &genparticles_phi, const std::string &genparticles_mass, - const std::string &reco_had_tau) { - // In nanoAODv12 the type of genparticle status flags / mother index were changed to UShort_t / Short_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); - auto [df2, genparticles_mother_index_column] = utility::Cast, ROOT::RVec>( - df1, genparticles_mother_index+"_v12", "ROOT::VecOps::RVec", genparticles_mother_index); +ROOT::RDF::RNode GenMatching(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &hadronic_gen_taus, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status_flags, + const std::string &genparticles_mother_index, + const std::string &genparticles_pt, + const std::string &genparticles_eta, + const std::string &genparticles_phi, + const std::string &genparticles_mass, + const std::string &reco_had_tau) { + // In nanoAODv12 the type of genparticle status flags / mother index were + // changed to UShort_t / Short_t. For v9 compatibility a type casting is + // applied. + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); + auto [df2, genparticles_mother_index_column] = + utility::Cast, ROOT::RVec>( + df1, genparticles_mother_index + "_v12", + "ROOT::VecOps::RVec", genparticles_mother_index); auto match_tau = [](const std::vector &had_gen_taus, - const ROOT::RVec &pdg_ids, - const ROOT::RVec &status_flags_v12, - const ROOT::RVec &mother_indices_v12, - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses, - const ROOT::Math::PtEtaPhiMVector &reco_had_tau) { + const ROOT::RVec &pdg_ids, + const ROOT::RVec &status_flags_v12, + const ROOT::RVec &mother_indices_v12, + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &masses, + const ROOT::Math::PtEtaPhiMVector &reco_had_tau) { auto status_flags = static_cast>(status_flags_v12); auto mother_indices = static_cast>(mother_indices_v12); // find closest lepton fulfilling the requirements @@ -656,8 +700,8 @@ ROOT::RDF::RNode GenMatching( int closest_genparticle_mother_statusFlag = 0; Logger::get("genparticles::tau::GenMatching") - ->debug("pdg_ids {}, status_flags {}, mother_indices {}", - pdg_ids, status_flags, mother_indices); + ->debug("pdg_ids {}, status_flags {}, mother_indices {}", pdg_ids, + status_flags, mother_indices); for (unsigned int i = 0; i < pdg_ids.size(); i++) { int pdgid = std::abs(pdg_ids.at(i)); @@ -669,18 +713,19 @@ ROOT::RDF::RNode GenMatching( bool statusbit = (IntBits(status_flags.at(i)).test(0) || IntBits(status_flags.at(i)).test(5)); if ((pdgid == 11 || pdgid == 13) && pts.at(i) > 8 && statusbit) { - ROOT::Math::PtEtaPhiMVector probe_gen_tau(pts.at(i), etas.at(i), - phis.at(i), masses.at(i)); + ROOT::Math::PtEtaPhiMVector probe_gen_tau( + pts.at(i), etas.at(i), phis.at(i), masses.at(i)); float delta_r = ROOT::Math::VectorUtil::DeltaR(probe_gen_tau, reco_had_tau); if (delta_r < min_delta_r) { Logger::get("genparticles::tau::GenMatching") ->debug("mother_index {}, pdg_id {}, status_flags {}", - mother_indices.at(i), pdg_ids.at(i), status_flags.at(i)); + mother_indices.at(i), pdg_ids.at(i), + status_flags.at(i)); if (mother_indices.at(i) == -1) { - // mother index of -1 means that there is no mother particle - // usually this happens for the particles of the initial pp - // collision + // mother index of -1 means that there is no mother + // particle usually this happens for the particles of + // the initial pp collision closest_genparticle_index = i; closest_genparticle_mother_pdgid = pdg_ids.at(i); closest_genparticle_mother_statusFlag = @@ -706,8 +751,8 @@ ROOT::RDF::RNode GenMatching( // check if the gen_tau is closer to the lepton than the // closest lepton genparticle ROOT::Math::PtEtaPhiMVector probe_gen_tau( - pts.at(gen_tau), etas.at(gen_tau), - phis.at(gen_tau), masses.at(gen_tau)); + pts.at(gen_tau), etas.at(gen_tau), phis.at(gen_tau), + masses.at(gen_tau)); float gen_tau_delta_r = ROOT::Math::VectorUtil::DeltaR(probe_gen_tau, reco_had_tau); // the decay is considered a hadronic decay (statusbit 5) if @@ -719,9 +764,9 @@ ROOT::RDF::RNode GenMatching( gen_tau_delta_r < min_delta_r) { // statusbit 5 is hadronic tau decay Logger::get("genparticles::tau::GenMatching") - ->debug( - "found hadronic gen. tau closer than closest lepton: {}", - gen_tau_delta_r); + ->debug("found hadronic gen. tau closer than closest " + "lepton: {}", + gen_tau_delta_r); Logger::get("genparticles::tau::GenMatching") ->debug("IS_TAU_HAD_DECAY"); return (int)MatchingGenTauCode::IS_TAU_HAD_DECAY; @@ -779,11 +824,12 @@ ROOT::RDF::RNode GenMatching( Logger::get("genparticles::tau::GenMatching")->debug("IS_FAKE"); return (int)MatchingGenTauCode::IS_FAKE; }; - auto df3 = df2.Define( - outputname, match_tau, - {hadronic_gen_taus, genparticles_pdg_id, genparticles_status_flags_column, - genparticles_mother_index_column, genparticles_pt, genparticles_eta, - genparticles_phi, genparticles_mass, reco_had_tau}); + auto df3 = df2.Define(outputname, match_tau, + {hadronic_gen_taus, genparticles_pdg_id, + genparticles_status_flags_column, + genparticles_mother_index_column, genparticles_pt, + genparticles_eta, genparticles_phi, + genparticles_mass, reco_had_tau}); return df3; } } // end namespace tau @@ -791,38 +837,37 @@ ROOT::RDF::RNode GenMatching( namespace drell_yan { /** - * @brief Extract the flavor of a leptonic Drell-Yan process from the LHE information. - * This function checks if exactly two final-state LHE leptons (electron, muon, tau) of - * the same flavor are present in the event. If so, the PDG ID of the lepton that the - * Z boson or the photon decays into is returned. If no such pair is found, the function - * returns -1. - * + * @brief Extract the flavor of a leptonic Drell-Yan process from the LHE + * information. This function checks if exactly two final-state LHE leptons + * (electron, muon, tau) of the same flavor are present in the event. If so, the + * PDG ID of the lepton that the Z boson or the photon decays into is returned. + * If no such pair is found, the function returns -1. + * * Possible values of the returned PDG ID are: * - 11 for a decay into an electron pair, * - 13 for a decay into a muon pair, * - 15 for a decay into a tau pair. - * + * * @param df input dataframe - * @param outputname name of the new column containing the PDG ID of the decay particles - * @param lhe_pdg_id name of the column containing the PDG ID values of the LHE particles - * @param lhe_status name of the column containing the status of the LHE particles - * + * @param outputname name of the new column containing the PDG ID of the decay + * particles + * @param lhe_pdg_id name of the column containing the PDG ID values of the LHE + * particles + * @param lhe_status name of the column containing the status of the LHE + * particles + * * @return a new dataframe with the decay flavor column added. */ -ROOT::RDF::RNode DecayFlavor( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_pdg_id, - const std::string &lhe_status -) { - auto flavor_flag = [] ( - const ROOT::RVec &lhe_pdg_id, - const ROOT::RVec &lhe_status - ) { - int decay_flavor_pdgid = -1; +ROOT::RDF::RNode DecayFlavor(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_pdg_id, + const std::string &lhe_status) { + auto flavor_flag = [](const ROOT::RVec &lhe_pdg_id, + const ROOT::RVec &lhe_status) { + int decay_flavor_pdgid = -1; const std::vector decay_flavors = {11, 13, 15}; for (const auto &decay_flavor : decay_flavors) { - if (ROOT::VecOps::Sum((lhe_status == 1) && (abs(lhe_pdg_id) == decay_flavor)) == 2) { + if (ROOT::VecOps::Sum((lhe_status == 1) && + (abs(lhe_pdg_id) == decay_flavor)) == 2) { decay_flavor_pdgid = decay_flavor; break; } @@ -830,11 +875,7 @@ ROOT::RDF::RNode DecayFlavor( return decay_flavor_pdgid; }; - return df.Define( - outputname, - flavor_flag, - {lhe_pdg_id, lhe_status} - ); + return df.Define(outputname, flavor_flag, {lhe_pdg_id, lhe_status}); } } // end namespace drell_yan diff --git a/src/htxs.cxx b/src/htxs.cxx index 0d39db8d..c3bfde61 100644 --- a/src/htxs.cxx +++ b/src/htxs.cxx @@ -89,8 +89,8 @@ ggH_WG1_uncertainties(ROOT::RDF::RNode df, return qcd_ggF_uncertSF_2017(njets, pth, flag); }, {htxs_flag, htxs_pth, htxs_njets}); - auto df2 = event::quantity::Unroll( - df1, weight_names, "ggH_WG1_uncertainties"); + auto df2 = event::quantity::Unroll(df1, weight_names, + "ggH_WG1_uncertainties"); return df2; } diff --git a/src/jets.cxx b/src/jets.cxx index d7f21890..107af811 100644 --- a/src/jets.cxx +++ b/src/jets.cxx @@ -29,49 +29,58 @@ namespace jet { * @param jet_raw_factor name of the column containing the raw factor for * each jet to get back to the raw jet \f$p_T\f$'s * - * @return a dataframe with a new column of raw jet \f$p_T\f$'s + * @return a dataframe with a new column of raw jet \f$p_T\f$'s */ -ROOT::RDF::RNode RawPt(ROOT::RDF::RNode df, - const std::string &outputname, +ROOT::RDF::RNode RawPt(ROOT::RDF::RNode df, const std::string &outputname, const std::string &jet_pt, const std::string &jet_raw_factor) { - return df.Define(outputname, + return df.Define( + outputname, [](const ROOT::RVec &pts, const ROOT::RVec &raw_factors) { ROOT::RVec raw_pts(pts.size()); for (size_t i = 0; i < pts.size(); ++i) { raw_pts.at(i) = pts.at(i) * (1 - raw_factors.at(i)); } return raw_pts; - }, {jet_pt, jet_raw_factor}); + }, + {jet_pt, jet_raw_factor}); } -/** +/** * @brief This function applies L1 energy corrections to raw jet momenta based - * on the recommendations of JetMET POG. More details: https://cms-jerc.web.cern.ch/JES/. - * It calculates corrected jet momenta for both standard and low-pt jets, and - * stores the results in the specified output columns. + * on the recommendations of JetMET POG. More details: + * https://cms-jerc.web.cern.ch/JES/. It calculates corrected jet momenta for + * both standard and low-pt jets, and stores the results in the specified output + * columns. * * The function needs both standard jets (> 15 GeV) and low-pt jets, and it - * calculates L1 corrected versions for the standard jets only and the combination - * of both which is need for the recalculation of MET (`met::Type1Correction`). + * calculates L1 corrected versions for the standard jets only and the + * combination of both which is need for the recalculation of MET + * (`met::Type1Correction`). * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * jet energy correction file - * @param outputname_L1 name of the output column for L1 corrected jet \f$p_T\f$'s + * @param outputname_L1 name of the output column for L1 corrected jet + * \f$p_T\f$'s * @param outputname_L1_T1MET name of the output column for L1 corrected jet - * \f$p_T\f$'s including low-pt jets, this is needed for the Type-1 MET correction + * \f$p_T\f$'s including low-pt jets, this is needed for the Type-1 MET + * correction * @param jet_raw_pt name of the column containing raw jet momenta * @param jet_eta name of the column containing jet pseudorapidity * @param jet_phi name of the column containing jet azimuthal angle * @param jet_area name of the column containing jet area - * @param jet_raw_muonfactor name of the column containing raw muon subtraction factors - * @param lowpt_jet_raw_pt name of the column containing raw momenta for low-pt jets - * @param lowpt_jet_eta name of the column containing pseudorapidity for low-pt jets - * @param lowpt_jet_phi name of the column containing azimuthal angle for low-pt jets + * @param jet_raw_muonfactor name of the column containing raw muon subtraction + * factors + * @param lowpt_jet_raw_pt name of the column containing raw momenta for low-pt + * jets + * @param lowpt_jet_eta name of the column containing pseudorapidity for low-pt + * jets + * @param lowpt_jet_phi name of the column containing azimuthal angle for low-pt + * jets * @param lowpt_jet_area name of the column containing area for low-pt jets - * @param lowpt_jet_raw_muonfactor name of the column containing raw muon subtraction - * factors for low-pt jets + * @param lowpt_jet_raw_muonfactor name of the column containing raw muon + * subtraction factors for low-pt jets * @param rho name of the column containing the event energy density * @param jec_file path to the JEC file containing the corrections * @param jec_algo name of the JEC algorithm use for jet reconstruction @@ -82,83 +91,83 @@ ROOT::RDF::RNode RawPt(ROOT::RDF::RNode df, * * @return a newdataframe with a two new column of L1 corrected jet \f$p_T\f$'s * - * @note This function can be used for both Run 2 and Run 3 as well as for data and MC. + * @note This function can be used for both Run 2 and Run 3 as well as for data + * and MC. */ -ROOT::RDF::RNode -PtCorrectionL1(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname_L1, - const std::string &outputname_L1_T1MET, - const std::string &jet_raw_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_area, - const std::string &jet_raw_muonfactor, - const std::string &lowpt_jet_raw_pt, - const std::string &lowpt_jet_eta, - const std::string &lowpt_jet_phi, - const std::string &lowpt_jet_area, - const std::string &lowpt_jet_raw_muonfactor, - const std::string &rho, - const std::string &jec_file, - const std::string &jec_algo, - const std::string &jes_tag) { - +ROOT::RDF::RNode PtCorrectionL1( + ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname_L1, const std::string &outputname_L1_T1MET, + const std::string &jet_raw_pt, const std::string &jet_eta, + const std::string &jet_phi, const std::string &jet_area, + const std::string &jet_raw_muonfactor, const std::string &lowpt_jet_raw_pt, + const std::string &lowpt_jet_eta, const std::string &lowpt_jet_phi, + const std::string &lowpt_jet_area, + const std::string &lowpt_jet_raw_muonfactor, const std::string &rho, + const std::string &jec_file, const std::string &jec_algo, + const std::string &jes_tag) { + // loading jet energy correction scale factor function auto jes_l1_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L1FastJet_" + jec_algo); - - auto L1_lambda = [jes_l1_evaluator]( - const ROOT::RVec &jet_raw_pts, - const ROOT::RVec &jet_etas, - const ROOT::RVec &jet_phis, - const ROOT::RVec &jet_areas, - const float &rho) { + auto L1_lambda = [jes_l1_evaluator](const ROOT::RVec &jet_raw_pts, + const ROOT::RVec &jet_etas, + const ROOT::RVec &jet_phis, + const ROOT::RVec &jet_areas, + const float &rho) { ROOT::RVec corrected_pts(jet_raw_pts.size()); for (std::size_t i = 0; i < jet_raw_pts.size(); ++i) { - float corr_factor = jes_l1_evaluator->evaluate({jet_areas.at(i), jet_etas.at(i), jet_raw_pts.at(i), rho}); + float corr_factor = jes_l1_evaluator->evaluate( + {jet_areas.at(i), jet_etas.at(i), jet_raw_pts.at(i), rho}); corrected_pts.at(i) = jet_raw_pts.at(i) * corr_factor; } return corrected_pts; }; - - auto L1_T1MET_lambda = [jes_l1_evaluator]( - const ROOT::RVec &jet_raw_pts, - const ROOT::RVec &jet_etas, - const ROOT::RVec &jet_phis, - const ROOT::RVec &jet_areas, - const ROOT::RVec &jet_muon_subtr_factors, - const ROOT::RVec &lowpt_jet_raw_pts, - const ROOT::RVec &lowpt_jet_etas, - const ROOT::RVec &lowpt_jet_phis, - const ROOT::RVec &lowpt_jet_areas, - const ROOT::RVec &lowpt_jet_muon_subtr_factors, - const float &rho) { - - ROOT::RVec corrected_pts(jet_raw_pts.size()+lowpt_jet_raw_pts.size()); - for (std::size_t i = 0; i < jet_raw_pts.size(); ++i) { - float pt_noMuRaw = jet_raw_pts.at(i) * (1 - jet_muon_subtr_factors.at(i)); - float corr_factor = jes_l1_evaluator->evaluate({jet_areas.at(i), jet_etas.at(i), jet_raw_pts.at(i), rho}); - corrected_pts.at(i) = pt_noMuRaw * corr_factor; - } - for (std::size_t i = 0; i < lowpt_jet_raw_pts.size(); ++i) { - float pt_noMuRaw = lowpt_jet_raw_pts.at(i) * (1.0 - lowpt_jet_muon_subtr_factors.at(i)); - float corr_factor = jes_l1_evaluator->evaluate({lowpt_jet_areas.at(i), lowpt_jet_etas.at(i), lowpt_jet_raw_pts.at(i), rho}); - corrected_pts.at(jet_raw_pts.size() + i) = pt_noMuRaw * corr_factor; - } - return corrected_pts; - }; + auto L1_T1MET_lambda = + [jes_l1_evaluator]( + const ROOT::RVec &jet_raw_pts, + const ROOT::RVec &jet_etas, + const ROOT::RVec &jet_phis, + const ROOT::RVec &jet_areas, + const ROOT::RVec &jet_muon_subtr_factors, + const ROOT::RVec &lowpt_jet_raw_pts, + const ROOT::RVec &lowpt_jet_etas, + const ROOT::RVec &lowpt_jet_phis, + const ROOT::RVec &lowpt_jet_areas, + const ROOT::RVec &lowpt_jet_muon_subtr_factors, + const float &rho) { + ROOT::RVec corrected_pts(jet_raw_pts.size() + + lowpt_jet_raw_pts.size()); + + for (std::size_t i = 0; i < jet_raw_pts.size(); ++i) { + float pt_noMuRaw = + jet_raw_pts.at(i) * (1 - jet_muon_subtr_factors.at(i)); + float corr_factor = jes_l1_evaluator->evaluate( + {jet_areas.at(i), jet_etas.at(i), jet_raw_pts.at(i), rho}); + corrected_pts.at(i) = pt_noMuRaw * corr_factor; + } + for (std::size_t i = 0; i < lowpt_jet_raw_pts.size(); ++i) { + float pt_noMuRaw = lowpt_jet_raw_pts.at(i) * + (1.0 - lowpt_jet_muon_subtr_factors.at(i)); + float corr_factor = jes_l1_evaluator->evaluate( + {lowpt_jet_areas.at(i), lowpt_jet_etas.at(i), + lowpt_jet_raw_pts.at(i), rho}); + corrected_pts.at(jet_raw_pts.size() + i) = + pt_noMuRaw * corr_factor; + } + return corrected_pts; + }; auto df1 = df.Define(outputname_L1, L1_lambda, {jet_raw_pt, jet_eta, jet_phi, jet_area, rho}); - auto df2 = df1.Define(outputname_L1_T1MET, L1_T1MET_lambda, - {jet_raw_pt, jet_eta, jet_phi, jet_area, - jet_raw_muonfactor, lowpt_jet_raw_pt, - lowpt_jet_eta, lowpt_jet_phi, lowpt_jet_area, - lowpt_jet_raw_muonfactor, rho}); + auto df2 = + df1.Define(outputname_L1_T1MET, L1_T1MET_lambda, + {jet_raw_pt, jet_eta, jet_phi, jet_area, jet_raw_muonfactor, + lowpt_jet_raw_pt, lowpt_jet_eta, lowpt_jet_phi, + lowpt_jet_area, lowpt_jet_raw_muonfactor, rho}); return df2; } @@ -171,7 +180,8 @@ PtCorrectionL1(ROOT::RDF::RNode df, * * The function needs both standard jets (> 15 GeV) and low-pt jets, and it * calculates fully corrected versions for the standard jets only and the - * combination of both which is need for the recalculation of MET (`met::Type1Correction`). + * combination of both which is need for the recalculation of MET + * (`met::Type1Correction`). * * Further, this function applies the jet energy resolution smearing to * simulated events, based on the JER correction factors provided by JME POG. @@ -184,7 +194,8 @@ PtCorrectionL1(ROOT::RDF::RNode df, * @param df input dataframe * @param correction_manager correction manager responsible for loading the * jet energy correction file - * @param outputname_L2L3 name of the output column for L2L3 corrected jet momenta + * @param outputname_L2L3 name of the output column for L2L3 corrected jet + * momenta * @param outputname_L2L3_T1MET name of the output column for L2L3 corrected jet * momenta for Type-1 MET correction (including low-pt jets) * @param jet_L1_pt name of the column containing L1 corrected jet momenta @@ -194,14 +205,16 @@ PtCorrectionL1(ROOT::RDF::RNode df, * @param jet_id name of the column containing jet IDs * @param jet_L1_T1MET_pt name of the column containing L1 corrected jet momenta * specifically for Type-1 MET correction, which includes low-pt jets - * @param lowpt_jet_eta name of the column containing low-pt jet pseudorapidities - * @param lowpt_jet_phi name of the column containing low-pt jet azimuthal angles + * @param lowpt_jet_eta name of the column containing low-pt jet + * pseudorapidities + * @param lowpt_jet_phi name of the column containing low-pt jet azimuthal + * angles * @param lowpt_jet_area name of the column containing low-pt jet area * @param gen_jet_pt name of the column containing generator-level jet momenta * @param gen_jet_eta name of the column containing generator-level jet * pseudorapidities - * @param gen_jet_phi name of the column containing generator-level jet azimuthal - * angles + * @param gen_jet_phi name of the column containing generator-level jet + * azimuthal angles * @param rho name of the column containing the event energy density * @param jer_seed seed value for the random number generator that is used for * the jet energy resolution smearing in MC simulated events @@ -213,44 +226,36 @@ PtCorrectionL1(ROOT::RDF::RNode df, * (e.g., "Summer19UL18_V5_MC", "Summer24Prompt24_V2_DATA") * @param jes_shift_sources list of JES shift sources for systematic * uncertainties - * @param jer_tag tag of the JER correction campaign (e.g., "Summer19UL18_JRV2_MC") + * @param jer_tag tag of the JER correction campaign (e.g., + * "Summer19UL18_JRV2_MC") * @param jes_shift JES shift variation (0 = nominal, +/-1 = up/down) * @param jer_shift JER shift variation ("nom", "up", or "down") - * @param era string defining the currently processed era, needed due to different - * kind of recommendations from JME POG for different eras (e.g., "2018", "2022preEE") + * @param era string defining the currently processed era, needed due to + * different kind of recommendations from JME POG for different eras (e.g., + * "2018", "2022preEE") * * @return a new dataframe with two columns for with fully corrected jet momenta * - * @note This function can be used for both Run 2 and Run 3 as well as for data and MC. - */ -ROOT::RDF::RNode -PtCorrectionL2L3(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname_L2L3, - const std::string &outputname_L2L3_T1MET, - const std::string &jet_L1_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_area, - const std::string &jet_id, - const std::string &jet_L1_T1MET_pt, - const std::string &lowpt_jet_eta, - const std::string &lowpt_jet_phi, - const std::string &lowpt_jet_area, - const std::string &gen_jet_pt, - const std::string &gen_jet_eta, - const std::string &gen_jet_phi, - const std::string &rho, - const std::string &jer_seed, - const std::string &run, - const std::string &jec_file, - const std::string &jec_algo, - const std::string &jes_tag, - const std::vector &jes_shift_sources, - const std::string &jer_tag, - const int &jes_shift, - const std::string &jer_shift, - const std::string &era) { + * @note This function can be used for both Run 2 and Run 3 as well as for data + * and MC. + */ +ROOT::RDF::RNode PtCorrectionL2L3( + ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname_L2L3, + const std::string &outputname_L2L3_T1MET, const std::string &jet_L1_pt, + const std::string &jet_eta, const std::string &jet_phi, + const std::string &jet_area, const std::string &jet_id, + const std::string &jet_L1_T1MET_pt, const std::string &lowpt_jet_eta, + const std::string &lowpt_jet_phi, const std::string &lowpt_jet_area, + const std::string &gen_jet_pt, const std::string &gen_jet_eta, + const std::string &gen_jet_phi, const std::string &rho, + const std::string &jer_seed, const std::string &run, + const std::string &jec_file, const std::string &jec_algo, + const std::string &jes_tag, + const std::vector &jes_shift_sources, + const std::string &jer_tag, const int &jes_shift, + const std::string &jer_shift, const std::string &era) { // identifying jet radius from algorithm float jet_radius = 0.4; @@ -265,8 +270,9 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, // In nanoAODv12 the type of jet/fatjet ID was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, jet_id_column] = utility::Cast, ROOT::RVec>( - df, jet_id+"_v12", "ROOT::VecOps::RVec", jet_id); + auto [df1, jet_id_column] = + utility::Cast, ROOT::RVec>( + df, jet_id + "_v12", "ROOT::VecOps::RVec", jet_id); // systematic sources std::vector jet_energy_scale_shifts; @@ -279,25 +285,22 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, } }; - // loading jet energy correction scale factor function + // loading jet energy correction scale factor function auto jes_l2_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L2Relative_" + jec_algo); auto jes_l2l3_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L2L3Residual_" + jec_algo); - - // Create a unified lambda that handles both era cases - auto jet_energy_scale_sf = [jes_l2_evaluator, jes_l2l3_evaluator, - is_data](const float eta, - const float pt, - const float phi, - const unsigned int run, - const std::string &era) { + // Create a unified lambda that handles both era cases + auto jet_energy_scale_sf = [jes_l2_evaluator, jes_l2l3_evaluator, is_data]( + const float eta, const float pt, + const float phi, const unsigned int run, + const std::string &era) { double l2 = 1.0; double l2l3 = 1.0; int era_year = std::stoi(era.substr(0, 4)); - + if (era_year <= 2022 || era == "2023preBPix") { l2 = jes_l2_evaluator->evaluate({eta, pt}); } else { @@ -305,9 +308,12 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, } if (is_data) { float _pt; - if (era == "2024" && pt < 30.0 && 2.0 < abs(eta) < 2.5) _pt = 30.0; - else _pt = pt; - l2l3 = jes_l2l3_evaluator->evaluate({static_cast(run), eta, _pt}); + if (era == "2024" && pt < 30.0 && 2.0 < abs(eta) < 2.5) + _pt = 30.0; + else + _pt = pt; + l2l3 = jes_l2l3_evaluator->evaluate( + {static_cast(run), eta, _pt}); } return l2 * l2l3; }; @@ -323,24 +329,22 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, // loading JER scale factor function auto jer_sf_evaluator = correction_manager.loadCorrection( - jec_file, jer_tag + "_ScaleFactor_" + jec_algo); - - auto correction_lambda = [jet_energy_scale_shifts, - jet_energy_scale_sf, jet_energy_resolution, - jer_sf_evaluator, jes_shift_sources, - jes_shift, jer_shift, jet_radius, era, is_data]( - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &area, - const ROOT::RVec &ids_v12, - const ROOT::RVec &gen_pts, - const ROOT::RVec &gen_etas, - const ROOT::RVec &gen_phis, - const float &rho, - const unsigned int &seed, - const unsigned int &run) { + jec_file, jer_tag + "_ScaleFactor_" + jec_algo); + auto correction_lambda = [jet_energy_scale_shifts, jet_energy_scale_sf, + jet_energy_resolution, jer_sf_evaluator, + jes_shift_sources, jes_shift, jer_shift, + jet_radius, era, is_data]( + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &area, + const ROOT::RVec &ids_v12, + const ROOT::RVec &gen_pts, + const ROOT::RVec &gen_etas, + const ROOT::RVec &gen_phis, + const float &rho, const unsigned int &seed, + const unsigned int &run) { // random value generator for jet smearing TRandom3 randm = TRandom3(seed); auto ids = static_cast>(ids_v12); @@ -351,14 +355,16 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, for (std::size_t i = 0; i < pts.size(); ++i) { // L1 already applied by previous producer float pt_corr = pts.at(i); - + // --- L2 and L2L3Residual (DATA only) - float corr_factor = jet_energy_scale_sf(etas.at(i), pt_corr, phis.at(i), run, era); + float corr_factor = + jet_energy_scale_sf(etas.at(i), pt_corr, phis.at(i), run, era); pt_corr *= corr_factor; Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("applying jet energy scale (L2-L3): L1 jet pt {} to corr. jet pt {}", - pts.at(i), pt_corr); + ->debug("applying jet energy scale (L2-L3): L1 jet pt {} to " + "corr. jet pt {}", + pts.at(i), pt_corr); // --- JES uncertainties and JER (MC only) --- if (!is_data) { @@ -368,38 +374,43 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, if (jet_energy_scale_shifts.size() == 1) { pt_scale_sf = 1. + - jes_shift * jet_energy_scale_shifts.at(0)->evaluate( - {etas.at(i), pt_corr}); + jes_shift * + jet_energy_scale_shifts.at(0)->evaluate( + {etas.at(i), pt_corr}); Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("JES shift of jet pt by {} for single source " - "with SF {}", jes_shift, pt_scale_sf); + ->debug("JES shift of jet pt by {} for single " + "source " + "with SF {}", + jes_shift, pt_scale_sf); } else { float quad_sum = 0.; - for (const auto &evaluator : jet_energy_scale_shifts) { - quad_sum += - std::pow(evaluator->evaluate( - {etas.at(i), pt_corr}), - 2.0); + for (const auto &evaluator : + jet_energy_scale_shifts) { + quad_sum += std::pow( + evaluator->evaluate({etas.at(i), pt_corr}), + 2.0); } pt_scale_sf = 1. + jes_shift * std::sqrt(quad_sum); Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("JES shift of jet pt by {} for multiple " - "sources with SF {}", - jes_shift, pt_scale_sf); + ->debug( + "JES shift of jet pt by {} for multiple " + "sources with SF {}", + jes_shift, pt_scale_sf); } } else if (jes_shift_sources.at(0) == "HEMIssue") { - // IDs are only present for the jet collection, not low pt jets - if (i < ids.size()) { + // IDs are only present for the jet collection, not low + // pt jets + if (i < ids.size()) { if (jes_shift == (-1.) && pt_corr > 15. && phis.at(i) > (-1.57) && phis.at(i) < (-0.87) && ids.at(i) == 2) { - if (etas.at(i) > (-2.5) && etas.at(i) < (-1.3)) - pt_scale_sf = 0.8; - else if (etas.at(i) > (-3.) && etas.at(i) <= (-2.5)) - pt_scale_sf = 0.65; + if (etas.at(i) > (-2.5) && etas.at(i) < (-1.3)) + pt_scale_sf = 0.8; + else if (etas.at(i) > (-3.) && + etas.at(i) <= (-2.5)) + pt_scale_sf = 0.65; } } - } pt_corr *= pt_scale_sf; } @@ -408,17 +419,20 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, float reso = jet_energy_resolution(etas.at(i), pt_corr, rho); float reso_sf = 1.0; if (era_year <= 2018) { // run 2 case - reso_sf = jer_sf_evaluator->evaluate({etas.at(i), jer_shift}); + reso_sf = + jer_sf_evaluator->evaluate({etas.at(i), jer_shift}); } else { // run 3 case - reso_sf = jer_sf_evaluator->evaluate({etas.at(i), pt_corr, jer_shift}); + reso_sf = jer_sf_evaluator->evaluate( + {etas.at(i), pt_corr, jer_shift}); } Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("Calculate JER {}: SF: {} resolution: {} ", jer_shift, - reso_sf, reso); + ->debug("Calculate JER {}: SF: {} resolution: {} ", + jer_shift, reso_sf, reso); float gen_pt_for_smear = default_float; // gen jet matching algorithm for JER - ROOT::Math::RhoEtaPhiVectorF jet(pt_corr, etas.at(i), phis.at(i)); + ROOT::Math::RhoEtaPhiVectorF jet(pt_corr, etas.at(i), + phis.at(i)); Logger::get("physicsobject::jet::PtCorrectionL2L3") ->debug("Going to smear jet: Eta: {} Phi: {} ", jet.Eta(), jet.Phi()); @@ -427,12 +441,13 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, ROOT::Math::RhoEtaPhiVectorF gen_jet( gen_pts.at(j), gen_etas.at(j), gen_phis.at(j)); Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("Checking gen Jet: Eta: {} Phi: {}", gen_jet.Eta(), - gen_jet.Phi()); + ->debug("Checking gen Jet: Eta: {} Phi: {}", + gen_jet.Eta(), gen_jet.Phi()); auto delta_r = ROOT::Math::VectorUtil::DeltaR(jet, gen_jet); if (delta_r > min_delta_r) continue; - if (delta_r < (jet_radius / 2.) && std::abs(pt_corr - gen_pts.at(j)) < + if (delta_r < (jet_radius / 2.) && + std::abs(pt_corr - gen_pts.at(j)) < (3.0 * reso * pt_corr)) { min_delta_r = delta_r; gen_pt_for_smear = gen_pts.at(j); @@ -442,20 +457,23 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, if (gen_pt_for_smear > 0.0) { Logger::get("physicsobject::jet::PtCorrectionL2L3") ->debug("Found gen jet for hybrid smearing method"); - jer_corr = (reso_sf - 1.0) * (pt_corr - gen_pt_for_smear) / pt_corr; + jer_corr = (reso_sf - 1.0) * (pt_corr - gen_pt_for_smear) / + pt_corr; } else { Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug("No gen jet found. Applying stochastic smearing."); - if (era_year >= 2022 && era_year <= 2024 && abs(etas.at(i)) > 2.5 && abs(etas.at(i)) < 3.0) { + ->debug( + "No gen jet found. Applying stochastic smearing."); + if (era_year >= 2022 && era_year <= 2024 && + abs(etas.at(i)) > 2.5 && abs(etas.at(i)) < 3.0) { Logger::get("physicsobject::jet::PtCorrectionL2L3") - ->debug( - "Jet has 3 > |eta| > 2.5, and no JER applied to " - "unmatched jets turned on." - ); + ->debug("Jet has 3 > |eta| > 2.5, and no JER " + "applied to " + "unmatched jets turned on."); jer_corr = 0.0; } else { - jer_corr = randm.Gaus(0, reso) * - std::sqrt(std::max(reso_sf * reso_sf - 1., 0.0)); + jer_corr = + randm.Gaus(0, reso) * + std::sqrt(std::max(reso_sf * reso_sf - 1., 0.0)); } } pt_corr *= std::max(0.0, 1.0 + jer_corr); @@ -466,32 +484,54 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, }; std::vector columns = { - jet_L1_pt, jet_eta, jet_phi, jet_area, jet_id_column, gen_jet_pt, - gen_jet_eta, gen_jet_phi, rho, jer_seed, run - }; + jet_L1_pt, jet_eta, jet_phi, jet_area, + jet_id_column, gen_jet_pt, gen_jet_eta, gen_jet_phi, + rho, jer_seed, run}; auto df2 = df1.Define(outputname_L2L3, correction_lambda, columns); - // get name of systematic variation to not over-define the same column multiple times in case of multiple systematic sources + // get name of systematic variation to not over-define the same column + // multiple times in case of multiple systematic sources std::string syst; size_t pos = outputname_L2L3_T1MET.find("__"); - if (pos != std::string::npos) syst = outputname_L2L3_T1MET.substr(pos); - else syst = ""; + if (pos != std::string::npos) + syst = outputname_L2L3_T1MET.substr(pos); + else + syst = ""; // Concatenate columns for jet collections - auto df3 = df2.Define("T1MET_etas"+syst, [](const ROOT::RVec& jet_etas, const ROOT::RVec& lowpt_jet_etas) { - return ROOT::VecOps::Concatenate(jet_etas, lowpt_jet_etas); - }, {jet_eta, lowpt_jet_eta}) - .Define("T1MET_phis"+syst, [](const ROOT::RVec& jet_phis, const ROOT::RVec& lowpt_jet_phis) { - return ROOT::VecOps::Concatenate(jet_phis, lowpt_jet_phis); - }, {jet_phi, lowpt_jet_phi}) - .Define("T1MET_area"+syst, [](const ROOT::RVec& jet_area, const ROOT::RVec& lowpt_jet_area) { - return ROOT::VecOps::Concatenate(jet_area, lowpt_jet_area); - }, {jet_area, lowpt_jet_area}); - - columns = { - jet_L1_T1MET_pt, "T1MET_etas"+syst, "T1MET_phis"+syst, "T1MET_area"+syst, - jet_id_column, gen_jet_pt, gen_jet_eta, gen_jet_phi, rho, jer_seed, run - }; + auto df3 = df2.Define("T1MET_etas" + syst, + [](const ROOT::RVec &jet_etas, + const ROOT::RVec &lowpt_jet_etas) { + return ROOT::VecOps::Concatenate(jet_etas, + lowpt_jet_etas); + }, + {jet_eta, lowpt_jet_eta}) + .Define("T1MET_phis" + syst, + [](const ROOT::RVec &jet_phis, + const ROOT::RVec &lowpt_jet_phis) { + return ROOT::VecOps::Concatenate(jet_phis, + lowpt_jet_phis); + }, + {jet_phi, lowpt_jet_phi}) + .Define("T1MET_area" + syst, + [](const ROOT::RVec &jet_area, + const ROOT::RVec &lowpt_jet_area) { + return ROOT::VecOps::Concatenate(jet_area, + lowpt_jet_area); + }, + {jet_area, lowpt_jet_area}); + + columns = {jet_L1_T1MET_pt, + "T1MET_etas" + syst, + "T1MET_phis" + syst, + "T1MET_area" + syst, + jet_id_column, + gen_jet_pt, + gen_jet_eta, + gen_jet_phi, + rho, + jer_seed, + run}; auto df4 = df3.Define(outputname_L2L3_T1MET, correction_lambda, columns); return df4; @@ -515,8 +555,9 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, * based on https://hypernews.cern.ch/HyperNews/CMS/get/JetMET/2000.html * * @warning This function is deprecated. It is recommended to use - * `physicsobject::jet::PtCorrectionL1` and `physicsobject::jet::PtCorrectionL2L3` - * instead for both Run 2 and Run 3 as well as for data and MC. + * `physicsobject::jet::PtCorrectionL1` and + * `physicsobject::jet::PtCorrectionL2L3` instead for both Run 2 and Run 3 as + * well as for data and MC. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -549,12 +590,12 @@ PtCorrectionL2L3(ROOT::RDF::RNode df, * should be reapplied * @param jes_shift JES shift variation (0 = nominal, +/-1 = up/down) * @param jer_shift JER shift variation ("nom", "up", or "down") - * @param era string defining the currently processed era, needed due to different - * kind of recommendations from JME POG for different eras + * @param era string defining the currently processed era, needed due to + * different kind of recommendations from JME POG for different eras * @param no_jer_for_unmatched_forward_jets if true, no jet energy resolution * smearing is applied to unmatched jets in the forward region * (\f$|\eta| > 2.5\f$). - * + * * @return a dataframe with a new column of corrected jet \f$p_T\f$'s * * @note If jets with \f$p_T\f$ > 15 GeV are corrected, this change should be @@ -578,14 +619,17 @@ PtCorrectionMC(ROOT::RDF::RNode df, const std::string &gen_jet_eta, const std::string &gen_jet_phi, const std::string &rho, const std::string &jer_seed, const std::string &jec_file, const std::string &jec_algo, - const std::string &jes_tag, const std::vector &jes_shift_sources, + const std::string &jes_tag, + const std::vector &jes_shift_sources, const std::string &jer_tag, bool reapply_jes, const int &jes_shift, const std::string &jer_shift, - const std::string &era, const bool &no_jer_for_unmatched_forward_jets = false) { + const std::string &era, + const bool &no_jer_for_unmatched_forward_jets = false) { // In nanoAODv12 the type of jet/fatjet ID was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, jet_id_column] = utility::Cast, ROOT::RVec>( - df, jet_id+"_v12", "ROOT::VecOps::RVec", jet_id); + auto [df1, jet_id_column] = + utility::Cast, ROOT::RVec>( + df, jet_id + "_v12", "ROOT::VecOps::RVec", jet_id); // identifying jet radius from algorithm float jet_radius = 0.4; @@ -605,7 +649,7 @@ PtCorrectionMC(ROOT::RDF::RNode df, // loading jet energy correction scale factor function auto jes_l1_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L1FastJet_" + jec_algo); - + auto jes_l2_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L2Relative_" + jec_algo); @@ -614,11 +658,12 @@ PtCorrectionMC(ROOT::RDF::RNode df, auto jes_evaluator = correction_manager.loadCompoundCorrection( jec_file, jes_tag + "_L1L2L3Res_" + jec_algo); - + // Create a unified lambda that handles both era cases - auto jet_energy_scale_sf = [jes_evaluator](const float area, const float eta, - const float pt, const float rho, - const float phi, const std::string era) { + auto jet_energy_scale_sf = [jes_evaluator](const float area, + const float eta, const float pt, + const float rho, const float phi, + const std::string era) { if (std::stoi(era.substr(0, 4)) <= 2022 || era == "2023preBPix") { // run 2 and 2022 to 2023preBPix cases return jes_evaluator->evaluate({area, eta, pt, rho}); @@ -642,23 +687,22 @@ PtCorrectionMC(ROOT::RDF::RNode df, // lambda run with dataframe auto correction_lambda = [reapply_jes, jet_energy_scale_shifts, jet_energy_scale_sf, jet_energy_resolution, - jer_sf_evaluator, jes_shift_sources, - jes_shift, jer_shift, jet_radius, - era, no_jer_for_unmatched_forward_jets]( - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &area, - const ROOT::RVec &raw_factors, - const ROOT::RVec &ids_v12, - const ROOT::RVec &gen_pts, - const ROOT::RVec &gen_etas, - const ROOT::RVec &gen_phis, - const float &rho, - const unsigned int &seed) { + jer_sf_evaluator, jes_shift_sources, jes_shift, + jer_shift, jet_radius, era, + no_jer_for_unmatched_forward_jets]( + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &area, + const ROOT::RVec &raw_factors, + const ROOT::RVec &ids_v12, + const ROOT::RVec &gen_pts, + const ROOT::RVec &gen_etas, + const ROOT::RVec &gen_phis, + const float &rho, const unsigned int &seed) { // random value generator for jet smearing TRandom3 randm = TRandom3(seed); - + auto ids = static_cast>(ids_v12); ROOT::RVec corrected_pts; for (int i = 0; i < pts.size(); i++) { @@ -666,8 +710,8 @@ PtCorrectionMC(ROOT::RDF::RNode df, if (reapply_jes) { // reapplying the JES correction float raw_pt = pts.at(i) * (1 - raw_factors.at(i)); - float corr = - jet_energy_scale_sf(area.at(i), etas.at(i), raw_pt, rho, phis.at(i), era); + float corr = jet_energy_scale_sf(area.at(i), etas.at(i), raw_pt, + rho, phis.at(i), era); corr_pt = raw_pt * corr; Logger::get("physicsobject::jet::PtCorrectionMC") ->debug("reapplying JE scale: orig. jet pt {} to raw " @@ -685,7 +729,8 @@ PtCorrectionMC(ROOT::RDF::RNode df, reso_sf = jer_sf_evaluator->evaluate({etas.at(i), jer_shift}); } else { // run 3 case - reso_sf = jer_sf_evaluator->evaluate({etas.at(i), corrected_pts.at(i), jer_shift}); + reso_sf = jer_sf_evaluator->evaluate( + {etas.at(i), corrected_pts.at(i), jer_shift}); } Logger::get("physicsobject::jet::PtCorrectionMC") ->debug("Calculate JER {}: SF: {} resolution: {} ", jer_shift, @@ -727,12 +772,11 @@ PtCorrectionMC(ROOT::RDF::RNode df, Logger::get("physicsobject::jet::PtCorrectionMC") ->debug("No gen jet found. Applying stochastic smearing."); double shift = 0.0; - if (no_jer_for_unmatched_forward_jets && abs(etas.at(i)) > 2.5) { + if (no_jer_for_unmatched_forward_jets && + abs(etas.at(i)) > 2.5) { Logger::get("physicsobject::jet::PtCorrectionMC") - ->debug( - "Jet has eta > 2.5, and no JER applied to " - "unmatched forward jets turned on." - ); + ->debug("Jet has eta > 2.5, and no JER applied to " + "unmatched forward jets turned on."); shift = 0.0; } else { shift = randm.Gaus(0, reso) * @@ -755,9 +799,10 @@ PtCorrectionMC(ROOT::RDF::RNode df, jes_shift * jet_energy_scale_shifts.at(0)->evaluate( {etas.at(i), corrected_pts.at(i)}); Logger::get("physicsobject::jet::PtCorrectionMC") - ->debug("JES shift of jet pt by {} for single source " - "with SF {}", - jes_shift, pt_scale_sf); + ->debug( + "JES shift of jet pt by {} for single source " + "with SF {}", + jes_shift, pt_scale_sf); } else { float quad_sum = 0.; for (const auto &evaluator : jet_energy_scale_shifts) { @@ -791,9 +836,9 @@ PtCorrectionMC(ROOT::RDF::RNode df, return corrected_pts; }; auto df2 = df1.Define(outputname, correction_lambda, - {jet_pt, jet_eta, jet_phi, jet_area, - jet_raw_factor, jet_id_column, gen_jet_pt, - gen_jet_eta, gen_jet_phi, rho, jer_seed}); + {jet_pt, jet_eta, jet_phi, jet_area, jet_raw_factor, + jet_id_column, gen_jet_pt, gen_jet_eta, gen_jet_phi, + rho, jer_seed}); return df2; } @@ -808,8 +853,9 @@ PtCorrectionMC(ROOT::RDF::RNode df, * are not necessary for data. * * @warning This function is deprecated. It is recommended to use - * `physicsobject::jet::PtCorrectionL1` and `physicsobject::jet::PtCorrectionL2L3` - * instead for both Run 2 and Run 3 as well as for data and MC. + * `physicsobject::jet::PtCorrectionL1` and + * `physicsobject::jet::PtCorrectionL2L3` instead for both Run 2 and Run 3 as + * well as for data and MC. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -828,8 +874,8 @@ PtCorrectionMC(ROOT::RDF::RNode df, * "AK8PFPuppi") * @param jes_tag tag of the JES correction campaign which is run dependent * (e.g., "Summer19UL18_RunA_V5_DATA") - * @param era string defining the currently processed era, needed due to different - * kind of recommendations from JME POG for different eras + * @param era string defining the currently processed era, needed due to + * different kind of recommendations from JME POG for different eras * * @return a dataframe with a new column of corrected jet \f$p_T\f$'s * @@ -850,8 +896,8 @@ PtCorrectionData(ROOT::RDF::RNode df, // loading jet energy correction scale factor function auto jes_l1_evaluator = correction_manager.loadCorrection( - jec_file, jes_tag + "_L1FastJet_" + jec_algo); - + jec_file, jes_tag + "_L1FastJet_" + jec_algo); + auto jes_l2_evaluator = correction_manager.loadCorrection( jec_file, jes_tag + "_L2Relative_" + jec_algo); @@ -859,38 +905,42 @@ PtCorrectionData(ROOT::RDF::RNode df, jec_file, jes_tag + "_L2L3Residual_" + jec_algo); auto jes_evaluator = correction_manager.loadCompoundCorrection( - jec_file, jes_tag + "_L1L2L3Res_" + jec_algo); - + jec_file, jes_tag + "_L1L2L3Res_" + jec_algo); + // Create a unified lambda that handles both era cases auto jet_energy_scale_sf = [jes_evaluator](const float area, const float eta, const float pt, - const float rho, const float phi, const unsigned int run, - const std::string era) { + const float rho, const float phi, + const unsigned int run, const std::string era) { if (std::stoi(era.substr(0, 4)) <= 2022) { // run 2 and 2022 cases return jes_evaluator->evaluate({area, eta, pt, rho}); } else if (era == "2023preBPix") { // run 3 2023preBPix - return jes_evaluator->evaluate({area, eta, pt, rho, (float)run}); + return jes_evaluator->evaluate( + {area, eta, pt, rho, (float)run}); } else { // run 3 from 2023postBpix onwards - return jes_evaluator->evaluate({area, eta, pt, rho, phi, (float)run}); + return jes_evaluator->evaluate( + {area, eta, pt, rho, phi, (float)run}); } }; auto correction_lambda = - [jes_tag, jet_energy_scale_sf, era]( - const ROOT::RVec &pts, const ROOT::RVec &etas, - const ROOT::RVec &phis, const ROOT::RVec &area, - const ROOT::RVec &raw_factors, const float &rho, - const unsigned int &run) { + [jes_tag, jet_energy_scale_sf, + era](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, const ROOT::RVec &area, + const ROOT::RVec &raw_factors, const float &rho, + const unsigned int &run) { ROOT::RVec corrected_pts; for (int i = 0; i < pts.size(); i++) { float corr_pt = pts.at(i); // reapplying the JES correction float raw_pt = pts.at(i) * (1 - raw_factors.at(i)); - float corr = jet_energy_scale_sf(area.at(i), etas.at(i), raw_pt, rho, phis.at(i), run, era); + float corr = + jet_energy_scale_sf(area.at(i), etas.at(i), raw_pt, rho, + phis.at(i), run, era); corr_pt = raw_pt * corr; Logger::get("physicsobject::jet::PtCorrectionData") @@ -898,14 +948,15 @@ PtCorrectionData(ROOT::RDF::RNode df, "pt {} to raw " "jet pt {} to recorr. jet pt {}", pts.at(i), raw_pt, corr_pt); - + corrected_pts.push_back(corr_pt); } return corrected_pts; }; - auto df1 = df.Define(outputname, correction_lambda, - {jet_pt, jet_eta, jet_phi, jet_area, jet_raw_factor, rho, run}); - return df1; + auto df1 = df.Define( + outputname, correction_lambda, + {jet_pt, jet_eta, jet_phi, jet_area, jet_raw_factor, rho, run}); + return df1; } else { auto df1 = df.Define(outputname, [](const ROOT::RVec &pts) { return pts; }, @@ -914,53 +965,54 @@ PtCorrectionData(ROOT::RDF::RNode df, } } -/** - * @brief This function applies a b-jet energy regression. The \f$p_T\f$ correction - * is applied to all b-jets identified with a b-tagging algorithm, e.g. DeepJet. - * The goal of the regression is to better estimate the energy of b-jets because - * compared to other jet flavors, b-jets have a significantly higher rate of leptons - * and therefore also neutrinos in the decay, which leads to a lower reconstructed energy. - * The correction is determined with a neural network that was trained to simultaneously - * estimate the b-jet energy and resolution. The application can be done on top of the - * general jet energy scale corrections. Ref. http://cds.cern.ch/record/2690804 +/** + * @brief This function applies a b-jet energy regression. The \f$p_T\f$ + * correction is applied to all b-jets identified with a b-tagging algorithm, + * e.g. DeepJet. The goal of the regression is to better estimate the energy of + * b-jets because compared to other jet flavors, b-jets have a significantly + * higher rate of leptons and therefore also neutrinos in the decay, which leads + * to a lower reconstructed energy. The correction is determined with a neural + * network that was trained to simultaneously estimate the b-jet energy and + * resolution. The application can be done on top of the general jet energy + * scale corrections. Ref. http://cds.cern.ch/record/2690804 * - * @note This function should only be used for Run2 since the regression was not further - * developed for Run3 and is also not present in the nanoAODs anymore. + * @note This function should only be used for Run2 since the regression was not + * further developed for Run3 and is also not present in the nanoAODs anymore. * * @param df input dataframe * @param outputname name of the output column for corrected b-jet \f$p_T\f$'s * @param jet_pt name of the column containing the jet \f$p_T\f$'s - * @param scale_factor name of the column containing the scale factors for the + * @param scale_factor name of the column containing the scale factors for the * b-jet \f$p_T\f$ - * @param bjet_mask name of the column containing the jet mask with identified + * @param bjet_mask name of the column containing the jet mask with identified * b-jets * * @return a dataframe with a new column */ -ROOT::RDF::RNode PtCorrectionBJets(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_pt, - const std::string &scale_factor, - const std::string &bjet_mask) { - auto bjet_pt_correction = [](const ROOT::RVec &pts, +ROOT::RDF::RNode PtCorrectionBJets(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &jet_pt, + const std::string &scale_factor, + const std::string &bjet_mask) { + auto bjet_pt_correction = [](const ROOT::RVec &pts, const ROOT::RVec &scale_factors, const ROOT::RVec &bjet_mask) { - ROOT::RVec corrected_pts; - for (int i = 0; i < pts.size(); i++) { - float corr_pt = pts.at(i); - if (bjet_mask.at(i)) { - // applying b jet energy correction - corr_pt = pts.at(i) * scale_factors.at(i); - Logger::get("physicsobject::jet::PtCorrectionBJets") - ->debug("applying b jet energy correction: orig. jet " - "pt {} to corrected " - "jet pt {} with correction factor {}", - pts.at(i), corr_pt, scale_factors.at(i)); - } - corrected_pts.push_back(corr_pt); + ROOT::RVec corrected_pts; + for (int i = 0; i < pts.size(); i++) { + float corr_pt = pts.at(i); + if (bjet_mask.at(i)) { + // applying b jet energy correction + corr_pt = pts.at(i) * scale_factors.at(i); + Logger::get("physicsobject::jet::PtCorrectionBJets") + ->debug("applying b jet energy correction: orig. jet " + "pt {} to corrected " + "jet pt {} with correction factor {}", + pts.at(i), corr_pt, scale_factors.at(i)); } - return corrected_pts; - }; + corrected_pts.push_back(corr_pt); + } + return corrected_pts; + }; auto df1 = df.Define(outputname, bjet_pt_correction, {jet_pt, scale_factor, bjet_mask}); @@ -995,8 +1047,9 @@ ROOT::RDF::RNode CutPileupID(ROOT::RDF::RNode df, const std::string &outputname, const float &pt_cut) { // In nanoAODv12 the type of jet PU ID was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, jet_pu_id_column] = utility::Cast, ROOT::RVec>( - df, jet_pu_id+"_v12", "ROOT::VecOps::RVec", jet_pu_id); + auto [df1, jet_pu_id_column] = + utility::Cast, ROOT::RVec>( + df, jet_pu_id + "_v12", "ROOT::VecOps::RVec", jet_pu_id); auto pass_pu_id = [pu_id_cut, pt_cut](const ROOT::RVec &pu_ids_v12, const ROOT::RVec &jet_pts) { @@ -1030,10 +1083,10 @@ ROOT::RDF::RNode CutPileupID(ROOT::RDF::RNode df, const std::string &outputname, */ ROOT::RDF::RNode VetoMap(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &jet_eta, - const std::string &jet_phi, const std::string &vetomap_file, - const std::string &vetomap_name, const std::string &vetomap_type) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &jet_eta, + const std::string &jet_phi, const std::string &vetomap_file, + const std::string &vetomap_name, const std::string &vetomap_type) { auto vetomap_evaluator = correction_manager.loadCorrection(vetomap_file, vetomap_name); @@ -1067,11 +1120,13 @@ VetoMap(ROOT::RDF::RNode df, /** * @brief Create a veto flag for events with jets in regions, which are known to * produce wrong measurements. The function checks for jets which pass the base - * selection criteria if they are in a eta-phi region with "hot" and/or "cold" towers. - * Events with any jet in such a region are vetoed in data and simulation. If the - * event is vetoed, a value of `true` is stored in the new column, otherwise `false`. - * The locations are provided by a `correctionlib` file and depend on the data-taking - * era. This procedure follows the official [JME POG recommendations](https://cms-jerc.web.cern.ch/Recommendations/#jet-veto-maps). + * selection criteria if they are in a eta-phi region with "hot" and/or "cold" + * towers. Events with any jet in such a region are vetoed in data and + * simulation. If the event is vetoed, a value of `true` is stored in the new + * column, otherwise `false`. The locations are provided by a `correctionlib` + * file and depend on the data-taking era. This procedure follows the official + * [JME POG + * recommendations](https://cms-jerc.web.cern.ch/Recommendations/#jet-veto-maps). * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -1081,87 +1136,81 @@ VetoMap(ROOT::RDF::RNode df, * @param jet_eta name of the column containing the jet pseudorapidities * @param jet_phi name of the column containing the jet azimuthal angles * @param jet_id name of the column containing the jet IDs - * @param jet_ch_em_ef name of the column containing the jet charged electromagnetic - * energy fraction - * @param jet_ne_em_ef name of the column containing the jet neutral electromagnetic - * energy fraction + * @param jet_ch_em_ef name of the column containing the jet charged + * electromagnetic energy fraction + * @param jet_ne_em_ef name of the column containing the jet neutral + * electromagnetic energy fraction * @param jet_vetomap_file file path to the correctionlib jet veto map * @param jet_vetomap_name name of the correction to access jet veto map * @param jet_vetomap_type jet veto map type; for analyses, this name should be * `"jetvetomap"`. * @param min_pt minimum transverse momentum for selected jets * @param id_wp working point for the jet identification - * @param max_em_frac maximum charged and neutral electromagnetic energy fraction - * for selected jets + * @param max_em_frac maximum charged and neutral electromagnetic energy + * fraction for selected jets * * @return a new data frame with the veto event mask column * * @note The veto map selection is mandatory for Run 3 analyses and can also be * applied to Run 2 analyses. */ -ROOT::RDF::RNode VetoMap( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &jet_pt, - const std::string &jet_eta, - const std::string &jet_phi, - const std::string &jet_id, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_vetomap_file, - const std::string &jet_vetomap_name, - const std::string &jet_vetomap_type, - const float &min_pt, - const int &id_wp, - const float &max_em_frac) { +ROOT::RDF::RNode +VetoMap(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &jet_pt, + const std::string &jet_eta, const std::string &jet_phi, + const std::string &jet_id, const std::string &jet_ch_em_ef, + const std::string &jet_ne_em_ef, const std::string &jet_vetomap_file, + const std::string &jet_vetomap_name, + const std::string &jet_vetomap_type, const float &min_pt, + const int &id_wp, const float &max_em_frac) { // In nanoAODv12 the type of jet/fatjet ID was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, jet_id_column] = utility::Cast, ROOT::RVec>( - df, jet_id+"_v12", "ROOT::VecOps::RVec", jet_id - ); + auto [df1, jet_id_column] = + utility::Cast, ROOT::RVec>( + df, jet_id + "_v12", "ROOT::VecOps::RVec", jet_id); // load the veto map evaluator - auto evaluator = correction_manager.loadCorrection(jet_vetomap_file, jet_vetomap_name); - - auto select = [ - evaluator, min_pt, id_wp, max_em_frac, jet_vetomap_type - ] ( - const ROOT::RVec &jet_pt, - const ROOT::RVec &jet_eta, - const ROOT::RVec &jet_phi, - const ROOT::RVec &jet_id_v12, - const ROOT::RVec &jet_ch_em_ef, - const ROOT::RVec &jet_ne_em_ef - ) { + auto evaluator = + correction_manager.loadCorrection(jet_vetomap_file, jet_vetomap_name); + + auto select = [evaluator, min_pt, id_wp, max_em_frac, + jet_vetomap_type](const ROOT::RVec &jet_pt, + const ROOT::RVec &jet_eta, + const ROOT::RVec &jet_phi, + const ROOT::RVec &jet_id_v12, + const ROOT::RVec &jet_ch_em_ef, + const ROOT::RVec &jet_ne_em_ef) { auto jet_id = static_cast>(jet_id_v12); // debug output for selection criteria and jet observables - Logger::get("physicsobject::jet::VetoMap")->debug("Create selection masks for jets"); - Logger::get("physicsobject::jet::VetoMap")->debug(" min_pt {}, id_wp {}, max_em_fraction {}", min_pt, id_wp, max_em_frac); + Logger::get("physicsobject::jet::VetoMap") + ->debug("Create selection masks for jets"); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" min_pt {}, id_wp {}, max_em_fraction {}", min_pt, + id_wp, max_em_frac); Logger::get("physicsobject::jet::VetoMap")->debug(" pt {}", jet_pt); - Logger::get("physicsobject::jet::VetoMap")->debug(" eta {}", jet_eta); - Logger::get("physicsobject::jet::VetoMap")->debug(" phi {}", jet_phi); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" eta {}", jet_eta); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" phi {}", jet_phi); Logger::get("physicsobject::jet::VetoMap")->debug(" id {}", jet_id); - Logger::get("physicsobject::jet::VetoMap")->debug(" ch_em_ef {}", jet_ch_em_ef); - Logger::get("physicsobject::jet::VetoMap")->debug(" n_em_ef {}", jet_ne_em_ef); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" ch_em_ef {}", jet_ch_em_ef); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" n_em_ef {}", jet_ne_em_ef); // create the index of selected jets auto jet_index = ROOT::VecOps::Nonzero( - (jet_pt > min_pt) - && (jet_id >= id_wp) - && ((jet_ch_em_ef + jet_ne_em_ef) < max_em_frac) - ); + (jet_pt > min_pt) && (jet_id >= id_wp) && + ((jet_ch_em_ef + jet_ne_em_ef) < max_em_frac)); // create container with indices for vetoed jets auto jet_index_vetoed = ROOT::RVec(0); for (const auto &i : jet_index) { // evaluate the jet veto map value - auto jet_vetoed = evaluator->evaluate({ - jet_vetomap_type, - jet_eta.at(i), - jet_phi.at(i) - }); + auto jet_vetoed = evaluator->evaluate( + {jet_vetomap_type, jet_eta.at(i), jet_phi.at(i)}); // if the jet is vetoed, add it to the vetoed jet index if (jet_vetoed) { @@ -1177,24 +1226,17 @@ ROOT::RDF::RNode VetoMap( // debug output for vetoes Logger::get("physicsobject::jet::VetoMap")->debug("Vetoes"); - Logger::get("physicsobject::jet::VetoMap")->debug(" jet_index_vetoed {}", jet_index_vetoed); - Logger::get("physicsobject::jet::VetoMap")->debug(" event_veto {}", event_veto); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" jet_index_vetoed {}", jet_index_vetoed); + Logger::get("physicsobject::jet::VetoMap") + ->debug(" event_veto {}", event_veto); return event_veto; }; return df1.Define( - outputname, - select, - { - jet_pt, - jet_eta, - jet_phi, - jet_id_column, - jet_ch_em_ef, - jet_ne_em_ef - } - ); + outputname, select, + {jet_pt, jet_eta, jet_phi, jet_id_column, jet_ch_em_ef, jet_ne_em_ef}); } /** @@ -1369,13 +1411,14 @@ namespace quantity { /** * @brief Patch for wrong Jet ID values in Run3 NanoAOD v12 samples. * - * The implementation follows the recipe by the [JME POG](https://twiki.cern.ch/twiki/bin/view/CMS/JetID13p6TeV#nanoAOD_Flags). + * The implementation follows the recipe by the [JME + * POG](https://twiki.cern.ch/twiki/bin/view/CMS/JetID13p6TeV#nanoAOD_Flags). * * @param df input dataframe * @param outputname name of the produced column * @param jet_pt name of the column with jet pt values * @param jet_eta name of the column with jet eta values - * @param jet_id name of the column with (broken) jet ID values + * @param jet_id name of the column with (broken) jet ID values * @param jet_ne_h_ef name of the column with neutral hadron energy fraction * @param jet_ne_em_ef name of the column with neutral EM energy fraction * @param jet_mu_ef name of the column with muon energy fraction @@ -1383,27 +1426,21 @@ namespace quantity { * * @return a dataframe with the new column */ -ROOT::RDF::RNode PatchedIDNanoV12( - ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &jet_pt, - const std::string &jet_eta, - const std::string &jet_id, - const std::string &jet_ne_h_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_mu_ef, - const std::string &jet_ch_em_ef -) { - // we do not need to ensure the correct casting for NanoAOD v9 samples here as this fix applies to NanoAOD v12 samples only - auto correction = [] ( - const ROOT::RVec &jet_pt, - const ROOT::RVec &jet_eta, - const ROOT::RVec &jet_id_v12, - const ROOT::RVec &jet_ne_h_ef, - const ROOT::RVec &jet_ne_em_ef, - const ROOT::RVec &jet_mu_ef, - const ROOT::RVec &jet_ch_em_ef - ) { +ROOT::RDF::RNode +PatchedIDNanoV12(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &jet_pt, const std::string &jet_eta, + const std::string &jet_id, const std::string &jet_ne_h_ef, + const std::string &jet_ne_em_ef, const std::string &jet_mu_ef, + const std::string &jet_ch_em_ef) { + // we do not need to ensure the correct casting for NanoAOD v9 samples here + // as this fix applies to NanoAOD v12 samples only + auto correction = [](const ROOT::RVec &jet_pt, + const ROOT::RVec &jet_eta, + const ROOT::RVec &jet_id_v12, + const ROOT::RVec &jet_ne_h_ef, + const ROOT::RVec &jet_ne_em_ef, + const ROOT::RVec &jet_mu_ef, + const ROOT::RVec &jet_ch_em_ef) { // cast jet_id to integer auto jet_id = static_cast>(jet_id_v12); @@ -1415,15 +1452,19 @@ ROOT::RDF::RNode PatchedIDNanoV12( if (abs(jet_eta.at(i)) <= 2.7) { pass_tight = jet_id.at(i) & (1 << 1); } else if (abs(jet_eta.at(i)) > 2.7 && abs(jet_eta.at(i)) <= 3.0) { - pass_tight = (jet_id.at(i) & (1 << 1)) && (jet_ne_h_ef.at(i) < 0.99); + pass_tight = + (jet_id.at(i) & (1 << 1)) && (jet_ne_h_ef.at(i) < 0.99); } else if (abs(jet_eta.at(i)) > 3.0) { - pass_tight = (jet_id.at(i) & (1 << 1)) && (jet_ne_em_ef.at(i) < 0.4); + pass_tight = + (jet_id.at(i) & (1 << 1)) && (jet_ne_em_ef.at(i) < 0.4); } - // evaluate if the jet passes the tight WP and fulfills the lepton veto + // evaluate if the jet passes the tight WP and fulfills the lepton + // veto bool pass_tight_lep_veto = false; if (abs(jet_eta.at(i)) <= 2.7) { - pass_tight_lep_veto = pass_tight && (jet_mu_ef.at(i) < 0.8) && (jet_ch_em_ef.at(i) < 0.8); + pass_tight_lep_veto = pass_tight && (jet_mu_ef.at(i) < 0.8) && + (jet_ch_em_ef.at(i) < 0.8); } else { pass_tight_lep_veto = pass_tight; } @@ -1444,36 +1485,30 @@ ROOT::RDF::RNode PatchedIDNanoV12( }; // redefine the data type of the Jet ID mask - return df.Define( - outputname, - correction, - { - jet_pt, - jet_eta, - jet_id, - jet_ne_h_ef, - jet_ne_em_ef, - jet_mu_ef, - jet_ch_em_ef - } - ); + return df.Define(outputname, correction, + {jet_pt, jet_eta, jet_id, jet_ne_h_ef, jet_ne_em_ef, + jet_mu_ef, jet_ch_em_ef}); } /** - * @brief Applies jet identification criteria based on JSON-defined jet ID corrections. + * @brief Applies jet identification criteria based on JSON-defined jet ID + * corrections. * - * This function loads jet ID definitions from correctionlib JSON files for the specified - * jet collection and evaluates two sets of criteria: + * This function loads jet ID definitions from correctionlib JSON files for the + * specified jet collection and evaluates two sets of criteria: * - Tight ID * - Tight Lepton Veto ID * - * It uses these evaluations to assign a jet ID code to each jet in the input dataframe: + * It uses these evaluations to assign a jet ID code to each jet in the input + * dataframe: * - 6 : passes Tight and Tight Lepton Veto IDs * - 2 : passes Tight ID but fails Tight Lepton Veto ID * - 0 : fails Tight ID - * (Ref. https://twiki.cern.ch/twiki/bin/view/CMS/JetID13p6TeV#Recommendations_for_the_13_6_AN1) + * (Ref. + * https://twiki.cern.ch/twiki/bin/view/CMS/JetID13p6TeV#Recommendations_for_the_13_6_AN1) * - * The jet ID is returned as a vector of `int`, compatible with NanoAOD v9 conventions. + * The jet ID is returned as a vector of `int`, compatible with NanoAOD v9 + * conventions. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -1482,76 +1517,79 @@ ROOT::RDF::RNode PatchedIDNanoV12( * @param jet_eta name of the branch for jet pseudorapidity * @param jet_ch_h_ef name of the branch for charged hadron energy fraction * @param jet_ne_h_ef name of the branch for neutral hadron energy fraction - * @param jet_ch_em_ef name of the branch for charged electromagnetic energy fraction - * @param jet_ne_em_ef name of the branch for neutral electromagnetic energy fraction + * @param jet_ch_em_ef name of the branch for charged electromagnetic energy + * fraction + * @param jet_ne_em_ef name of the branch for neutral electromagnetic energy + * fraction * @param jet_mu_ef name of the branch for muon energy fraction - * @param jet_ch_mult name of the branch for number of charged particles in a jet - * @param jet_ne_mult name of the branch for number of neutral particles in a jet - * @param jet_id_file path to the jet ID JSON file containing correction definitions - * @param jet_name prefix of the jet collection used to select the appropriate corrections + * @param jet_ch_mult name of the branch for number of charged particles in a + * jet + * @param jet_ne_mult name of the branch for number of neutral particles in a + * jet + * @param jet_id_file path to the jet ID JSON file containing correction + * definitions + * @param jet_name prefix of the jet collection used to select the appropriate + * corrections * * @return a new dataframe with the new jet ID column appended */ -ROOT::RDF::RNode +ROOT::RDF::RNode ID(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &jet_eta, - const std::string &jet_ch_h_ef, - const std::string &jet_ne_h_ef, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &jet_mu_ef, - const std::string &jet_ch_mult, - const std::string &jet_ne_mult, - const std::string &jet_id_file, - const std::string &jet_name) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &jet_eta, + const std::string &jet_ch_h_ef, const std::string &jet_ne_h_ef, + const std::string &jet_ch_em_ef, const std::string &jet_ne_em_ef, + const std::string &jet_mu_ef, const std::string &jet_ch_mult, + const std::string &jet_ne_mult, const std::string &jet_id_file, + const std::string &jet_name) { // Load the jet ID correction file with Tight criteria - auto tightID = - correction_manager.loadCorrection(jet_id_file, jet_name + "_Tight"); - - // Load the jet ID correction file with TightLeptonVeto criteria - auto tightLepVetoID = - correction_manager.loadCorrection(jet_id_file, jet_name + "_TightLeptonVeto"); - - auto compute_jet_id = [tightID, tightLepVetoID]( - const ROOT::RVec &eta, - const ROOT::RVec &ch_h_ef, - const ROOT::RVec &ne_h_ef, - const ROOT::RVec &ch_em_ef, - const ROOT::RVec &ne_em_ef, - const ROOT::RVec &mu_ef, - const ROOT::RVec &ch_mult, - const ROOT::RVec &ne_mult) { + auto tightID = + correction_manager.loadCorrection(jet_id_file, jet_name + "_Tight"); + // Load the jet ID correction file with TightLeptonVeto criteria + auto tightLepVetoID = correction_manager.loadCorrection( + jet_id_file, jet_name + "_TightLeptonVeto"); + + auto compute_jet_id = [tightID, + tightLepVetoID](const ROOT::RVec &eta, + const ROOT::RVec &ch_h_ef, + const ROOT::RVec &ne_h_ef, + const ROOT::RVec &ch_em_ef, + const ROOT::RVec &ne_em_ef, + const ROOT::RVec &mu_ef, + const ROOT::RVec &ch_mult, + const ROOT::RVec &ne_mult) { size_t nJets = eta.size(); - ROOT::RVec jetId(nJets); + ROOT::RVec jetId(nJets); for (size_t i = 0; i < nJets; ++i) { UChar_t mult = ch_mult.at(i) + ne_mult.at(i); bool passTight = false, passTightLepVeto = false; - passTight = (tightID->evaluate( - {eta.at(i), ch_h_ef.at(i), ne_h_ef.at(i), ch_em_ef.at(i), - ne_em_ef.at(i), mu_ef.at(i), ch_mult.at(i), ne_mult.at(i), mult} - ) > 0.5); - - passTightLepVeto = (tightLepVetoID->evaluate( - {eta.at(i), ch_h_ef.at(i), ne_h_ef.at(i), ch_em_ef.at(i), - ne_em_ef.at(i), mu_ef.at(i), ch_mult.at(i), ne_mult.at(i), mult} - ) > 0.5); - - if (passTight && passTightLepVeto) jetId[i] = 6; - else if (passTight && !passTightLepVeto) jetId[i] = 2; - else jetId[i] = 0; + passTight = + (tightID->evaluate({eta.at(i), ch_h_ef.at(i), ne_h_ef.at(i), + ch_em_ef.at(i), ne_em_ef.at(i), mu_ef.at(i), + ch_mult.at(i), ne_mult.at(i), mult}) > 0.5); + + passTightLepVeto = + (tightLepVetoID->evaluate( + {eta.at(i), ch_h_ef.at(i), ne_h_ef.at(i), ch_em_ef.at(i), + ne_em_ef.at(i), mu_ef.at(i), ch_mult.at(i), ne_mult.at(i), + mult}) > 0.5); + + if (passTight && passTightLepVeto) + jetId[i] = 6; + else if (passTight && !passTightLepVeto) + jetId[i] = 2; + else + jetId[i] = 0; } return jetId; }; auto df1 = df.Define(outputname, compute_jet_id, - {jet_eta, jet_ch_h_ef, jet_ne_h_ef, - jet_ch_em_ef, jet_ne_em_ef, jet_mu_ef, - jet_ch_mult, jet_ne_mult}); + {jet_eta, jet_ch_h_ef, jet_ne_h_ef, jet_ch_em_ef, + jet_ne_em_ef, jet_mu_ef, jet_ch_mult, jet_ne_mult}); return df1; } } // end namespace quantity @@ -1559,16 +1597,17 @@ ID(ROOT::RDF::RNode df, namespace scalefactor { /** - * @brief This function calculates the b-tagging scale factor. The scale + * @brief This function calculates the b-tagging scale factor. The scale * factor corrects inconsistencies in the b-tagging efficiency between data and - * simulation. The scale factors are loaded from a correctionlib file + * simulation. The scale factors are loaded from a correctionlib file * using a specified scale factor name and variation. * - * This producer is optimized for evaluating b-tagging scale factors for a - * full shape correction of the b-tagging discriminant (DeepJet). Working point + * This producer is optimized for evaluating b-tagging scale factors for a + * full shape correction of the b-tagging discriminant (DeepJet). Working point * based scale factors have different dependencies. * - * More information from BTV POG can be found here https://btv-wiki.docs.cern.ch/ScaleFactors/ + * More information from BTV POG can be found here + * https://btv-wiki.docs.cern.ch/ScaleFactors/ * * and about the correctionlib files: * - [UL2018 b-tagging @@ -1583,7 +1622,8 @@ namespace scalefactor { * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file - * @param outputname name of the output column containing the b-tagging scale factor + * @param outputname name of the output column containing the b-tagging scale + * factor * @param pt name of the column containing the transverse momenta of jets * @param eta name of the column containing the pseudorapidity of jets * @param btag_value name of the column containing the btag values of jets @@ -1591,11 +1631,13 @@ namespace scalefactor { * @param flavor name of the column containing the flavors of jets, usually used * flavors are: 5=b-jet, 4=c-jet, 0=light jet (g, u, d, s) * @param jet_mask name of the column containing the mask for good/selected jets - * @param bjet_mask name of the column containing themask for good/selected b-jets - * @param jet_veto_mask name of the column containing the veto mask for + * @param bjet_mask name of the column containing themask for good/selected + * b-jets + * @param jet_veto_mask name of the column containing the veto mask for * overlapping jets (e.g. with selected lepton pairs) * @param sf_file path to the file with the b-tagging scale factors - * @param sf_name name of the b-tagging scale factor correction e.g. "deepJet_shape" + * @param sf_name name of the b-tagging scale factor correction e.g. + * "deepJet_shape" * @param variation name the scale factor variation, available values: * central, down_*, up_* (* name of specific variation) * @@ -1606,23 +1648,24 @@ namespace scalefactor { */ ROOT::RDF::RNode BtaggingShape(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &btag_value, - const std::string &flavor, const std::string &jet_mask, - const std::string &bjet_mask, const std::string &jet_veto_mask, - const std::string &sf_file, const std::string &sf_name, - const std::string &variation) { - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug( - "Setting up functions for b-tag sf with correctionlib"); - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug("Correction algorithm - Name {}", - sf_name); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &btag_value, + const std::string &flavor, const std::string &jet_mask, + const std::string &bjet_mask, const std::string &jet_veto_mask, + const std::string &sf_file, const std::string &sf_name, + const std::string &variation) { + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("Setting up functions for b-tag sf with correctionlib"); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("Correction algorithm - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - + // In nanoAODv12 the type of jet flavor was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, flavor_column] = utility::Cast, ROOT::RVec>( - df, flavor+"_v12", "ROOT::VecOps::RVec", flavor); + auto [df1, flavor_column] = + utility::Cast, ROOT::RVec>( + df, flavor + "_v12", "ROOT::VecOps::RVec", flavor); auto btagSF_lambda = [evaluator, variation](const ROOT::RVec &pts, @@ -1633,42 +1676,39 @@ BtaggingShape(ROOT::RDF::RNode df, const ROOT::RVec &bjet_mask, const ROOT::RVec &jet_veto_mask) { auto flavors = static_cast>(flavors_v12); - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug("Variation - Name {}", variation); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("Variation - Name {}", variation); float sf = 1.; for (int i = 0; i < pts.size(); i++) { - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug( - "jet masks - jet {}, b-jet {}, jet veto {}", jet_mask.at(i), - bjet_mask.at(i), jet_veto_mask.at(i)); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("jet masks - jet {}, b-jet {}, jet veto {}", + jet_mask.at(i), bjet_mask.at(i), jet_veto_mask.at(i)); // considering only good jets/b-jets, this is needed since jets and // bjets might have different quality cuts depending on the analysis if ((jet_mask.at(i) || bjet_mask.at(i)) && jet_veto_mask.at(i)) { - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug( - "SF - pt {}, eta {}, btag value {}, flavor {}", - pts.at(i), etas.at(i), btag_values.at(i), - flavors.at(i)); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("SF - pt {}, eta {}, btag value {}, flavor {}", + pts.at(i), etas.at(i), btag_values.at(i), + flavors.at(i)); float jet_sf = 1.; // considering only phase space where the scale factors are // defined - if ( - pts.at(i) >= 20.0 - && pts.at(i) < 10000.0 - && std::abs(etas.at(i)) < 2.5 - && !(std::isnan(btag_values.at(i)) || btag_values.at(i) == -1.0) - ) { + if (pts.at(i) >= 20.0 && pts.at(i) < 10000.0 && + std::abs(etas.at(i)) < 2.5 && + !(std::isnan(btag_values.at(i)) || + btag_values.at(i) == -1.0)) { // for c-jet related uncertainties only scale factors of // c-jets are varied, the rest is nominal/central if (variation.find("cferr") != std::string::npos) { // flavor=4 means c-flavor if (flavors.at(i) == 4) { jet_sf = evaluator->evaluate( - {variation, flavors.at(i), - std::abs(etas.at(i)), pts.at(i), - btag_values.at(i)}); + {variation, flavors.at(i), std::abs(etas.at(i)), + pts.at(i), btag_values.at(i)}); } else { jet_sf = evaluator->evaluate( - {"central", flavors.at(i), - std::abs(etas.at(i)), pts.at(i), - btag_values.at(i)}); + {"central", flavors.at(i), std::abs(etas.at(i)), + pts.at(i), btag_values.at(i)}); } } // for nominal/central and all other uncertainties c-jets @@ -1677,55 +1717,59 @@ BtaggingShape(ROOT::RDF::RNode df, else { if (flavors.at(i) != 4) { jet_sf = evaluator->evaluate( - {variation, flavors.at(i), - std::abs(etas.at(i)), pts.at(i), - btag_values.at(i)}); + {variation, flavors.at(i), std::abs(etas.at(i)), + pts.at(i), btag_values.at(i)}); } else { jet_sf = evaluator->evaluate( - {"central", flavors.at(i), - std::abs(etas.at(i)), pts.at(i), - btag_values.at(i)}); + {"central", flavors.at(i), std::abs(etas.at(i)), + pts.at(i), btag_values.at(i)}); } } } - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug("Jet Scale Factor {}", jet_sf); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("Jet Scale Factor {}", jet_sf); sf *= jet_sf; } }; - Logger::get("physicsobject::jet::scalefactor::BtaggingShape")->debug("Event Scale Factor {}", sf); + Logger::get("physicsobject::jet::scalefactor::BtaggingShape") + ->debug("Event Scale Factor {}", sf); return sf; }; - auto df2 = df1.Define( - outputname, btagSF_lambda, - {pt, eta, btag_value, flavor_column, jet_mask, bjet_mask, jet_veto_mask}); + auto df2 = df1.Define(outputname, btagSF_lambda, + {pt, eta, btag_value, flavor_column, jet_mask, + bjet_mask, jet_veto_mask}); return df2; } /** - * @brief This function calculates the b-tagging scale factor. The scale + * @brief This function calculates the b-tagging scale factor. The scale * factor corrects inconsistencies in the b-tagging efficiency between data and - * simulation. The scale factors are loaded from a correctionlib file + * simulation. The scale factors are loaded from a correctionlib file * using a specified scale factor name and variation. * - * This producer can be used to evaluate working point based scale factors. It is - * defined based on scale factors provided by BTV POG for Run3 2024. + * This producer can be used to evaluate working point based scale factors. It + * is defined based on scale factors provided by BTV POG for Run3 2024. * - * More information from BTV POG can be found here https://btv-wiki.docs.cern.ch/ScaleFactors/ + * More information from BTV POG can be found here + * https://btv-wiki.docs.cern.ch/ScaleFactors/ * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file - * @param outputname name of the output column containing the b-tagging scale factor + * @param outputname name of the output column containing the b-tagging scale + * factor * @param pt name of the column containing the transverse momenta of jets * @param eta name of the column containing the pseudorapidity of jets * @param flavor name of the column containing the flavors of jets, usually used * flavors are: 5=b-jet, 4=c-jet, 0=light jet (g, u, d, s) * @param jet_mask name of the column containing the mask for good/selected jets - * @param bjet_mask name of the column containing the mask for good/selected b-jets - * @param jet_veto_mask name of the column containing the veto mask for + * @param bjet_mask name of the column containing the mask for good/selected + * b-jets + * @param jet_veto_mask name of the column containing the veto mask for * overlapping jets (e.g. with selected lepton pairs) * @param sf_file path to the file with the b-tagging scale factors - * @param sf_name name of the b-tagging scale factor correction e.g. "deepJet_shape" + * @param sf_name name of the b-tagging scale factor correction e.g. + * "deepJet_shape" * @param variation name the scale factor variation, available values: * central, down_*, up_* (* name of specific variation) * @param btag_wp string that specifies the b-tagging working point used in an @@ -1735,60 +1779,63 @@ BtaggingShape(ROOT::RDF::RNode df, */ ROOT::RDF::RNode BtaggingWP(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &pt, - const std::string &eta, const std::string &flavor, - const std::string &jet_mask, - const std::string &bjet_mask, const std::string &jet_veto_mask, - const std::string &sf_file, const std::string &sf_name, - const std::string &variation, const std::string &btag_wp) { - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug( - "Setting up functions for wp based b-tag sf with correctionlib"); - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug("Correction algorithm - Name {}", - sf_name); + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &flavor, + const std::string &jet_mask, const std::string &bjet_mask, + const std::string &jet_veto_mask, const std::string &sf_file, + const std::string &sf_name, const std::string &variation, + const std::string &btag_wp) { + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug( + "Setting up functions for wp based b-tag sf with correctionlib"); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("Correction algorithm - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); // In nanoAODv12 the type of jet flavor was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, flavor_column] = utility::Cast, ROOT::RVec>( - df, flavor+"_v12", "ROOT::VecOps::RVec", flavor); - - auto btagSF_lambda = [evaluator, - variation, btag_wp]( - const ROOT::RVec &etas, - const ROOT::RVec &pts, - const ROOT::RVec &flavors_v12, - const ROOT::RVec &jet_mask, - const ROOT::RVec &bjet_mask, - const ROOT::RVec &jet_veto_mask) { + auto [df1, flavor_column] = + utility::Cast, ROOT::RVec>( + df, flavor + "_v12", "ROOT::VecOps::RVec", flavor); + + auto btagSF_lambda = [evaluator, variation, + btag_wp](const ROOT::RVec &etas, + const ROOT::RVec &pts, + const ROOT::RVec &flavors_v12, + const ROOT::RVec &jet_mask, + const ROOT::RVec &bjet_mask, + const ROOT::RVec &jet_veto_mask) { auto flavors = static_cast>(flavors_v12); - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug("Variation - Name {}", variation); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("Variation - Name {}", variation); float sf = 1.; for (int i = 0; i < pts.size(); i++) { - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug( - "jet masks - jet {}, b-jet {}, jet veto {}", jet_mask.at(i), - bjet_mask.at(i), jet_veto_mask.at(i)); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("jet masks - jet {}, b-jet {}, jet veto {}", + jet_mask.at(i), bjet_mask.at(i), jet_veto_mask.at(i)); // considering only good jets/b-jets, this is needed since jets and // bjets might have different quality cuts depending on the analysis if ((jet_mask.at(i) || bjet_mask.at(i)) && jet_veto_mask.at(i)) { - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug( - "SF - pt {}, eta {}, btag wp {}, flavor {}", - pts.at(i), etas.at(i), btag_wp, - flavors.at(i)); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("SF - pt {}, eta {}, btag wp {}, flavor {}", + pts.at(i), etas.at(i), btag_wp, flavors.at(i)); float jet_sf = 1.; // considering only phase space where the scale factors are // defined if (pts.at(i) >= 20.0 && pts.at(i) < 10000.0 && std::abs(etas.at(i)) < 2.5) { - jet_sf = evaluator->evaluate( - {variation, btag_wp, flavors.at(i), - std::abs(etas.at(i)), pts.at(i)}); + jet_sf = + evaluator->evaluate({variation, btag_wp, flavors.at(i), + std::abs(etas.at(i)), pts.at(i)}); } - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug("Jet Scale Factor {}", jet_sf); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("Jet Scale Factor {}", jet_sf); sf *= jet_sf; } }; - Logger::get("physicsobject::jet::scalefactor::BtaggingWP")->debug("Event Scale Factor {}", sf); + Logger::get("physicsobject::jet::scalefactor::BtaggingWP") + ->debug("Event Scale Factor {}", sf); return sf; }; auto df2 = df1.Define( diff --git a/src/lorentzvectors.cxx b/src/lorentzvectors.cxx index fa9d2544..5de5698e 100644 --- a/src/lorentzvectors.cxx +++ b/src/lorentzvectors.cxx @@ -10,53 +10,55 @@ namespace lorentzvector { /** - * @brief This function builds a Lorentz vector for a single object with given - * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. The object - * is specified by an index from an `index_vector`. This function utilizes the - * [PtEtaPhiMVector from ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). + * @brief This function builds a Lorentz vector for a single object with given + * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. The object + * is specified by an index from an `index_vector`. This function utilizes the + * [PtEtaPhiMVector from + * ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). * * @param df input dataframe * @param outputname name of the output column containing the Lorentz vector - * @param pt name of the column containing the \f$p_T\f$ values of an object + * @param pt name of the column containing the \f$p_T\f$ values of an object * for the Lorentz vector - * @param eta name of the column containing the \f$\eta\f$ values of an object + * @param eta name of the column containing the \f$\eta\f$ values of an object * for the Lorentz vector - * @param phi name of the column containing the \f$\phi\f$ values of an object + * @param phi name of the column containing the \f$\phi\f$ values of an object * for the Lorentz vector - * @param mass name of the column containing the mass values of an object + * @param mass name of the column containing the mass values of an object * for the Lorentz vector * @param index_vector name of the column containing indices of objects - * @param position position in the index vector that specifies for which object + * @param position position in the index vector that specifies for which object * in the object vector the Lorentz vector should be build * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, - const std::string &index_vector, - const int position) { +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass, + const std::string &index_vector, const int position) { Logger::get("lorentzvector::Build")->debug("Building {}", outputname); auto df1 = df.Define( outputname, - [position](const ROOT::RVec &pts, const ROOT::RVec &etas, const ROOT::RVec &phis, - const ROOT::RVec &masses, const ROOT::RVec &index_vector) { + [position](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &masses, + const ROOT::RVec &index_vector) { ROOT::Math::PtEtaPhiMVector p4; try { const int index = index_vector.at(position); - Logger::get("lorentzvector::Build")->debug("Used object {} with quantities pt {}, eta {}, phi {}, mass {}", - index, pts.at(index), etas.at(index), phis.at(index), masses.at(index)); - p4 = ROOT::Math::PtEtaPhiMVector(pts.at(index), etas.at(index), phis.at(index), masses.at(index)); - } - catch (const std::out_of_range &e) { + Logger::get("lorentzvector::Build") + ->debug("Used object {} with quantities pt {}, eta {}, phi " + "{}, mass {}", + index, pts.at(index), etas.at(index), + phis.at(index), masses.at(index)); + p4 = ROOT::Math::PtEtaPhiMVector(pts.at(index), etas.at(index), + phis.at(index), + masses.at(index)); + } catch (const std::out_of_range &e) { p4 = ROOT::Math::PtEtaPhiMVector(default_float, default_float, default_float, default_float); } - Logger::get("lorentzvector::Build") - ->debug("P4 : {}", p4); + Logger::get("lorentzvector::Build")->debug("P4 : {}", p4); return p4; }, {pt, eta, phi, mass, index_vector}); @@ -64,49 +66,51 @@ ROOT::RDF::RNode Build(ROOT::RDF::RNode df, } /** - * @brief This function builds a Lorentz vector for a single object with given - * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. The object is specified - * by an `index`. This function utilizes the [PtEtaPhiMVector from ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). + * @brief This function builds a Lorentz vector for a single object with given + * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. The object + * is specified by an `index`. This function utilizes the [PtEtaPhiMVector from + * ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). * * @param df input dataframe * @param outputname name of the output column containing the Lorentz vector - * @param pt name of the column containing the \f$p_T\f$ values of an object + * @param pt name of the column containing the \f$p_T\f$ values of an object * for the Lorentz vector - * @param eta name of the column containing the \f$\eta\f$ values of an object + * @param eta name of the column containing the \f$\eta\f$ values of an object * for the Lorentz vector - * @param phi name of the column containing the \f$\phi\f$ values of an object + * @param phi name of the column containing the \f$\phi\f$ values of an object * for the Lorentz vector - * @param mass name of the column containing the mass values of an object + * @param mass name of the column containing the mass values of an object * for the Lorentz vector - * @param index index of an object that specifies for which object in the object vector - * the Lorentz vector should be build + * @param index index of an object that specifies for which object in the object + * vector the Lorentz vector should be build * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass, const int index) { Logger::get("lorentzvector::Build")->debug("Building {}", outputname); auto df1 = df.Define( outputname, - [index](const ROOT::RVec &pts, const ROOT::RVec &etas, const ROOT::RVec &phis, - const ROOT::RVec &masses) { + [index](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &masses) { ROOT::Math::PtEtaPhiMVector p4; try { - Logger::get("lorentzvector::Build")->debug("Used object {} with quantities pt {}, eta {}, phi {}, mass {}", - index, pts.at(index), etas.at(index), phis.at(index), masses.at(index)); - p4 = ROOT::Math::PtEtaPhiMVector(pts.at(index), etas.at(index), phis.at(index), masses.at(index)); - } - catch (const std::out_of_range &e) { + Logger::get("lorentzvector::Build") + ->debug("Used object {} with quantities pt {}, eta {}, phi " + "{}, mass {}", + index, pts.at(index), etas.at(index), + phis.at(index), masses.at(index)); + p4 = ROOT::Math::PtEtaPhiMVector(pts.at(index), etas.at(index), + phis.at(index), + masses.at(index)); + } catch (const std::out_of_range &e) { p4 = ROOT::Math::PtEtaPhiMVector(default_float, default_float, default_float, default_float); } - Logger::get("lorentzvector::Build") - ->debug("P4 : {}", p4); + Logger::get("lorentzvector::Build")->debug("P4 : {}", p4); return p4; }, {pt, eta, phi, mass}); @@ -114,42 +118,43 @@ ROOT::RDF::RNode Build(ROOT::RDF::RNode df, } /** - * @brief This function builds a Lorentz vector for a single particle with given - * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. This function - * utilizes the [PtEtaPhiMVector from ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). + * @brief This function builds a Lorentz vector for a single particle with given + * kinematic values for \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass. This + * function utilizes the [PtEtaPhiMVector from + * ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). * * @param df input dataframe * @param outputname name of the output column containing the Lorentz vector - * @param pt name of the column containing the \f$p_T\f$ value for the Lorentz vector - * @param eta name of the column containing the \f$\eta\f$ value for the Lorentz vector - * @param phi name of the column containing the \f$\phi\f$ value for the Lorentz vector - * @param mass name of the column containing the mass value for the Lorentz vector + * @param pt name of the column containing the \f$p_T\f$ value for the Lorentz + * vector + * @param eta name of the column containing the \f$\eta\f$ value for the Lorentz + * vector + * @param phi name of the column containing the \f$\phi\f$ value for the Lorentz + * vector + * @param mass name of the column containing the mass value for the Lorentz + * vector * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Build(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass) { +ROOT::RDF::RNode Build(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, const std::string &mass) { Logger::get("lorentzvector::Build")->debug("Building {}", outputname); auto df1 = df.Define( outputname, [](const float &pt, const float &eta, const float &phi, - const float &mass) { - Logger::get("lorentzvector::Build")->debug("Used object quantities pt {}, eta {}, phi {}, mass {}", - pt, eta, phi, mass); + const float &mass) { + Logger::get("lorentzvector::Build") + ->debug("Used object quantities pt {}, eta {}, phi {}, mass {}", + pt, eta, phi, mass); ROOT::Math::PtEtaPhiMVector p4; if (pt >= 0.) { p4 = ROOT::Math::PtEtaPhiMVector(pt, eta, phi, mass); - } - else { + } else { p4 = ROOT::Math::PtEtaPhiMVector(default_float, default_float, default_float, default_float); } - Logger::get("lorentzvector::Build") - ->debug("P4 : {}", p4); + Logger::get("lorentzvector::Build")->debug("P4 : {}", p4); return p4; }, {pt, eta, phi, mass}); @@ -157,21 +162,25 @@ ROOT::RDF::RNode Build(ROOT::RDF::RNode df, } /** - * @brief This function builds a Lorentz vector for the missing transverse - * momentum/energy (MET) with given kinematic values for \f$p_T\f$ and \f$\phi\f$. - * For MET, \f$\eta\f$ and the mass are assumed to be zero. This function - * utilizes the [PtEtaPhiMVector from ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). + * @brief This function builds a Lorentz vector for the missing transverse + * momentum/energy (MET) with given kinematic values for \f$p_T\f$ and + * \f$\phi\f$. For MET, \f$\eta\f$ and the mass are assumed to be zero. This + * function utilizes the [PtEtaPhiMVector from + * ROOT](https://root.cern/doc/master/namespaceROOT_1_1Math.html#a6cea5921731c7ac99dea921fb188df31). * * @param df input dataframe * @param outputname name of the output column containing the missing transverse * energy Lorentz vector - * @param met_pt name of the column containing the \f$p_T\f$ value for the Lorentz vector - * @param met_phi name of the column containing the \f$\phi\f$ value for the Lorentz vector + * @param met_pt name of the column containing the \f$p_T\f$ value for the + * Lorentz vector + * @param met_phi name of the column containing the \f$\phi\f$ value for the + * Lorentz vector * * @return a new dataframe containing the new column */ ROOT::RDF::RNode BuildMET(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &met_pt, const std::string &met_phi) { + const std::string &met_pt, + const std::string &met_phi) { auto construct_metvector = [](const float &pt, const float &phi) { // for Met, eta and mass is zero auto met = ROOT::Math::PtEtaPhiMVector(pt, 0., phi, 0.); @@ -181,111 +190,122 @@ ROOT::RDF::RNode BuildMET(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief Build a new column with a collection of Lorentz vectors per dataframe entry, which are - * created from the \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns of a collection (e.g. jets or muons). + * @brief Build a new column with a collection of Lorentz vectors per dataframe + * entry, which are created from the \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass + * columns of a collection (e.g. jets or muons). * - * For instance, this can be used to create four-vector objects from the four-vector component - * columns of a NanoAOD collection. + * For instance, this can be used to create four-vector objects from the + * four-vector component columns of a NanoAOD collection. * - * The function expects \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns, which contain `ROOT::VecOps::RVec` - * objects. In addition, the argument `object_mask` must point to a column which contains - * index lists of type `ROOT::VecOps::RVec`. These index lists contain the indices of - * elements, for which four-vectors should be build. The output column contains a vector of - * four-vectors `ROOT::VecOps::RVec` and only contains - * the elements, which have been selected in by applying the `object_mask`. + * The function expects \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns, + * which contain `ROOT::VecOps::RVec` objects. In addition, the argument + * `object_mask` must point to a column which contains index lists of type + * `ROOT::VecOps::RVec`. These index lists contain the indices of elements, + * for which four-vectors should be build. The output column contains a vector + * of four-vectors `ROOT::VecOps::RVec` and only contains the + * elements, which have been selected in by applying the `object_mask`. * * @param df input dataframe - * @param outputname name of the output column containing the collection vector + * @param outputname name of the output column containing the collection vector * of Lorentz vectors - * @param pt name of the column containing the \f$p_T\f$ values of the object collection - * @param eta name of the column containing the \f$\eta\f$ values of the object collection - * @param phi name of the column containing the \f$\phi\f$ values of the object collection - * @param mass name of the column containing the mass values of the object collection - * @param object_mask name of the mask column indicating selected objects to only calculate - * the four-vectors for selected objects + * @param pt name of the column containing the \f$p_T\f$ values of the object + * collection + * @param eta name of the column containing the \f$\eta\f$ values of the object + * collection + * @param phi name of the column containing the \f$\phi\f$ values of the object + * collection + * @param mass name of the column containing the mass values of the object + * collection + * @param object_mask name of the mask column indicating selected objects to + * only calculate the four-vectors for selected objects * * @return a new dataframe containing the new column */ ROOT::RDF::RNode BuildCollection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass, - const std::string &object_mask) { - auto build_p4_collection = [](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses, - const ROOT::RVec &object_mask) { - auto pts_ = ROOT::VecOps::Take(pts, object_mask); - auto etas_ = ROOT::VecOps::Take(etas, object_mask); - auto phis_ = ROOT::VecOps::Take(phis, object_mask); - auto masses_ = ROOT::VecOps::Take(masses, object_mask); - return ROOT::VecOps::Construct(pts_, etas_, phis_, masses_); - }; - return df.Define(outputname, build_p4_collection, {pt, eta, phi, mass, object_mask}); + const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, + const std::string &mass, + const std::string &object_mask) { + auto build_p4_collection = + [](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, const ROOT::RVec &masses, + const ROOT::RVec &object_mask) { + auto pts_ = ROOT::VecOps::Take(pts, object_mask); + auto etas_ = ROOT::VecOps::Take(etas, object_mask); + auto phis_ = ROOT::VecOps::Take(phis, object_mask); + auto masses_ = ROOT::VecOps::Take(masses, object_mask); + return ROOT::VecOps::Construct( + pts_, etas_, phis_, masses_); + }; + return df.Define(outputname, build_p4_collection, + {pt, eta, phi, mass, object_mask}); } -/** - * @brief Build a new column with a collection of Lorentz vectors per dataframe entry, which are - * created from the \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns of a collection (e.g. jets or muons). +/** + * @brief Build a new column with a collection of Lorentz vectors per dataframe + * entry, which are created from the \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass + * columns of a collection (e.g. jets or muons). * - * For instance, this can be used to create four-vector objects from the four-vector component - * columns of a NanoAOD collection. + * For instance, this can be used to create four-vector objects from the + * four-vector component columns of a NanoAOD collection. * - * The function expects \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns, which contain `ROOT::VecOps::RVec` - * objects. The output column contains four-vectors `ROOT::VecOps::RVec`. + * The function expects \f$p_T\f$, \f$\eta\f$, \f$\phi\f$ and mass columns, + * which contain `ROOT::VecOps::RVec` objects. The output column contains + * four-vectors `ROOT::VecOps::RVec`. * * @param df input dataframe - * @param outputname name of the output column containing the collection vector + * @param outputname name of the output column containing the collection vector * of Lorentz vectors - * @param pt name of the column containing the \f$p_T\f$ values of the object collection - * @param eta name of the column containing the \f$\eta\f$ values of the object collection - * @param phi name of the column containing the \f$\phi\f$ values of the object collection - * @param mass name of the column containing the mass values of the object collection + * @param pt name of the column containing the \f$p_T\f$ values of the object + * collection + * @param eta name of the column containing the \f$\eta\f$ values of the object + * collection + * @param phi name of the column containing the \f$\phi\f$ values of the object + * collection + * @param mass name of the column containing the mass values of the object + * collection * * @return a new dataframe containing the new column */ ROOT::RDF::RNode BuildCollection(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &phi, - const std::string &mass) { - auto build_p4_collection = [](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses) { - return ROOT::VecOps::Construct(pts, etas, phis, masses); - }; + const std::string &outputname, + const std::string &pt, const std::string &eta, + const std::string &phi, + const std::string &mass) { + auto build_p4_collection = + [](const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &phis, const ROOT::RVec &masses) { + return ROOT::VecOps::Construct( + pts, etas, phis, masses); + }; return df.Define(outputname, build_p4_collection, {pt, eta, phi, mass}); } /** - * @brief This function is scaling the \f$p_T\f$ and mass (therefore also energy) - * of a Lorentz vector by a given scale factor. + * @brief This function is scaling the \f$p_T\f$ and mass (therefore also + * energy) of a Lorentz vector by a given scale factor. * * @param df input dataframe - * @param outputname name of the output column containing the scaled Lorentz vector + * @param outputname name of the output column containing the scaled Lorentz + * vector * @param vector name of the column containing the Lorentz vector to be scaled * @param scalefactor scale factor value that should be applied * * @return a new dataframe containing the new column */ ROOT::RDF::RNode Scale(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector, - const float &scalefactor) { - return df.Define( - outputname, - [scalefactor](const ROOT::Math::PtEtaPhiMVector &p4) { - if (p4.pt() < 0.0) - return ROOT::Math::PtEtaPhiMVector( - default_float, default_float, default_float, default_float); - auto p4_scaled = p4 * scalefactor; - return p4_scaled; - }, - {vector}); + const std::string &vector, const float &scalefactor) { + return df.Define(outputname, + [scalefactor](const ROOT::Math::PtEtaPhiMVector &p4) { + if (p4.pt() < 0.0) + return ROOT::Math::PtEtaPhiMVector( + default_float, default_float, default_float, + default_float); + auto p4_scaled = p4 * scalefactor; + return p4_scaled; + }, + {vector}); } } // end namespace lorentzvector #endif /* GUARD_LORENTZVECTORS_H */ \ No newline at end of file diff --git a/src/met.cxx b/src/met.cxx index 20768342..4b531150 100644 --- a/src/met.cxx +++ b/src/met.cxx @@ -3,18 +3,18 @@ #include "../include/RecoilCorrections/MetSystematics.hxx" #include "../include/RecoilCorrections/RecoilCorrector.hxx" -#include "../include/utility/CorrectionManager.hxx" -#include "../include/event.hxx" #include "../include/defaults.hxx" +#include "../include/event.hxx" +#include "../include/utility/CorrectionManager.hxx" #include "../include/utility/Logger.hxx" #include "ROOT/RDataFrame.hxx" #include "ROOT/RVec.hxx" #include "bitset" +#include "correction.h" #include #include #include #include -#include "correction.h" typedef std::bitset<20> IntBits; @@ -24,13 +24,15 @@ namespace met { * @brief This function is used to apply recoil corrections on a given sample. * It is only recommented to apply it to single boson samples, like Z, W or * Higgs boson. The corrections are provided by the HLepRare group. For more - * information on how the recoil corrections were calculated and have to be used, - * check out [this presentation](https://indico.cern.ch/event/1583951/contributions/6751916/attachments/3159171/5612627/HLepRare_25.10.22.pdf). - * and the HLepRare group [documentation](https://cms-higgs-leprare.docs.cern.ch/htt-common/V_recoil/). + * information on how the recoil corrections were calculated and have to be + * used, check out [this + * presentation](https://indico.cern.ch/event/1583951/contributions/6751916/attachments/3159171/5612627/HLepRare_25.10.22.pdf). + * and the HLepRare group + * [documentation](https://cms-higgs-leprare.docs.cern.ch/htt-common/V_recoil/). * - * @note This function is intended to be used in Run3 where recoil corrections are - * provided in json files to be read by correctionlib. For Run2 recoil correction - * see the overloaded version of this function. + * @note This function is intended to be used in Run3 where recoil corrections + * are provided in json files to be read by correctionlib. For Run2 recoil + * correction see the overloaded version of this function. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -42,14 +44,16 @@ namespace met { * Lorentz vector * @param p4_vis_gen_boson name of the column containing the visible part of * the generator-level boson Lorentz vector - * @param n_jets name of the column containing the number of good jets in an event + * @param n_jets name of the column containing the number of good jets in an + * event * @param corr_file path to the json file with the recoil corrections * @param corr_name name of the recoil correction, this is the first part of the * correction string in the json file (e.g. "Recoil_correction") - * @param method method to be used to apply the corrections, possible options are - * "Rescaling", "QuantileMapHist" and "Uncertainty" (second part of the correction string) - * @param order order of the used DY samples: "LO" for madgraph, "NLO" for amc\@nlo, - * "NNLO" for powheg + * @param method method to be used to apply the corrections, possible options + * are "Rescaling", "QuantileMapHist" and "Uncertainty" (second part of the + * correction string) + * @param order order of the used DY samples: "LO" for madgraph, "NLO" for + * amc\@nlo, "NNLO" for powheg * @param variation name of the variation that should be evaluated, options are * "nom", "RespUp", "RespDown", "ResolUp", "ResolDown". This is only used if * `method` is set to "Uncertainty". @@ -58,107 +62,149 @@ namespace met { * * @return a new dataframe containing the new MET column */ -ROOT::RDF::RNode RecoilCorrection( - ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &p4_met, const std::string &p4_gen_boson, - const std::string &p4_vis_gen_boson, const std::string &n_jets, - const std::string &corr_file, const std::string &corr_name, - const std::string &method, const std::string &order, - const std::string &variation, bool apply_correction) { +ROOT::RDF::RNode +RecoilCorrection(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &p4_met, + const std::string &p4_gen_boson, + const std::string &p4_vis_gen_boson, const std::string &n_jets, + const std::string &corr_file, const std::string &corr_name, + const std::string &method, const std::string &order, + const std::string &variation, bool apply_correction) { if (apply_correction) { - Logger::get("met::RecoilCorrection")->debug("Will run recoil corrections with correctionlib"); - + Logger::get("met::RecoilCorrection") + ->debug("Will run recoil corrections with correctionlib"); + // Rescaling method is the only recommended method for outside // -150 GeV < UPara, UPerp < 150 GeV - auto RecoilCorr = correction_manager.loadCorrection(corr_file, corr_name + "_" + method); + auto RecoilCorr = correction_manager.loadCorrection( + corr_file, corr_name + "_" + method); auto Correction = [RecoilCorr, order, method, variation]( - ROOT::Math::PtEtaPhiMVector &met, - ROOT::Math::PtEtaPhiMVector &gen_boson, - ROOT::Math::PtEtaPhiMVector &vis_gen_boson, - const int &n_jets) { - // For Run3 jets with pT > 30 GeV and |eta| < 2.5 or pT > 50 GeV outside the tracker region - // need to be considered (avoid jet horn region) - // type of n_jets needs to be a float for the correctionlib evaluation + ROOT::Math::PtEtaPhiMVector &met, + ROOT::Math::PtEtaPhiMVector &gen_boson, + ROOT::Math::PtEtaPhiMVector &vis_gen_boson, + const int &n_jets) { + // For Run3 jets with pT > 30 GeV and |eta| < 2.5 or pT > 50 GeV + // outside the tracker region need to be considered (avoid jet horn + // region) type of n_jets needs to be a float for the correctionlib + // evaluation float nJets = static_cast(n_jets); - float genPt = gen_boson.Pt(); // generator Z(W) pT + float genPt = gen_boson.Pt(); // generator Z(W) pT ROOT::Math::PtEtaPhiMVector met_new; Logger::get("met::RecoilCorrection")->debug("Corrector Inputs"); Logger::get("met::RecoilCorrection")->debug("N jets {} ", nJets); - Logger::get("met::RecoilCorrection")->debug("gen. boson Px {} ", gen_boson.Px()); - Logger::get("met::RecoilCorrection")->debug("gen. boson Py {} ", gen_boson.Py()); - Logger::get("met::RecoilCorrection")->debug("vis. gen. boson Px {} ", vis_gen_boson.Px()); - Logger::get("met::RecoilCorrection")->debug("vis. gen. boson Py {} ", vis_gen_boson.Py()); - Logger::get("met::RecoilCorrection")->debug("old MET X {} ", met.Px()); - Logger::get("met::RecoilCorrection")->debug("old MET Y {} ", met.Py()); - Logger::get("met::RecoilCorrection")->debug("old MET {} ", met.Pt()); + Logger::get("met::RecoilCorrection") + ->debug("gen. boson Px {} ", gen_boson.Px()); + Logger::get("met::RecoilCorrection") + ->debug("gen. boson Py {} ", gen_boson.Py()); + Logger::get("met::RecoilCorrection") + ->debug("vis. gen. boson Px {} ", vis_gen_boson.Px()); + Logger::get("met::RecoilCorrection") + ->debug("vis. gen. boson Py {} ", vis_gen_boson.Py()); + Logger::get("met::RecoilCorrection") + ->debug("old MET X {} ", met.Px()); + Logger::get("met::RecoilCorrection") + ->debug("old MET Y {} ", met.Py()); + Logger::get("met::RecoilCorrection") + ->debug("old MET {} ", met.Pt()); if (std::isnan(met.Px()) || std::isnan(met.Py())) { - Logger::get("met::RecoilCorrection")->debug("NaN detected in MET, returning uncorrected MET"); + Logger::get("met::RecoilCorrection") + ->debug("NaN detected in MET, returning uncorrected MET"); return met; - } - else { + } else { if (method == "Rescaling" || method == "QuantileMapHist") { - ROOT::Math::PtEtaPhiMVector U = met + vis_gen_boson - gen_boson; + ROOT::Math::PtEtaPhiMVector U = + met + vis_gen_boson - gen_boson; float dPhi_U = U.Phi() - gen_boson.Phi(); float Upara = U.Pt() * std::cos(dPhi_U); float Uperp = U.Pt() * std::sin(dPhi_U); - Logger::get("met::RecoilCorrection")->debug("dPhi_U {} ", dPhi_U); - Logger::get("met::RecoilCorrection")->debug("Upara {} ", Upara); - Logger::get("met::RecoilCorrection")->debug("Uperp {} ", Uperp); - - float Upara_new = RecoilCorr->evaluate({order, nJets, genPt, "Upara", Upara}); - float Uperp_new = RecoilCorr->evaluate({order, nJets, genPt, "Uperp", Uperp}); - Logger::get("met::RecoilCorrection")->debug("Upara_new {} ", Upara_new); - Logger::get("met::RecoilCorrection")->debug("Uperp_new {} ", Uperp_new); - - float Upt_new = std::sqrt(Upara_new*Upara_new + Uperp_new*Uperp_new); - float Uphi_new = std::atan2(Uperp_new, Upara_new) + gen_boson.Phi(); - Logger::get("met::RecoilCorrection")->debug("Upt_new {} ", Upt_new); - Logger::get("met::RecoilCorrection")->debug("Uphi_new {} ", Uphi_new); - - ROOT::Math::PtEtaPhiMVector U_new = ROOT::Math::PtEtaPhiMVector(Upt_new, 0., Uphi_new, 0.); + Logger::get("met::RecoilCorrection") + ->debug("dPhi_U {} ", dPhi_U); + Logger::get("met::RecoilCorrection") + ->debug("Upara {} ", Upara); + Logger::get("met::RecoilCorrection") + ->debug("Uperp {} ", Uperp); + + float Upara_new = RecoilCorr->evaluate( + {order, nJets, genPt, "Upara", Upara}); + float Uperp_new = RecoilCorr->evaluate( + {order, nJets, genPt, "Uperp", Uperp}); + Logger::get("met::RecoilCorrection") + ->debug("Upara_new {} ", Upara_new); + Logger::get("met::RecoilCorrection") + ->debug("Uperp_new {} ", Uperp_new); + + float Upt_new = std::sqrt(Upara_new * Upara_new + + Uperp_new * Uperp_new); + float Uphi_new = + std::atan2(Uperp_new, Upara_new) + gen_boson.Phi(); + Logger::get("met::RecoilCorrection") + ->debug("Upt_new {} ", Upt_new); + Logger::get("met::RecoilCorrection") + ->debug("Uphi_new {} ", Uphi_new); + + ROOT::Math::PtEtaPhiMVector U_new = + ROOT::Math::PtEtaPhiMVector(Upt_new, 0., Uphi_new, 0.); met_new = U_new - vis_gen_boson + gen_boson; - } - else if (method == "Uncertainty") { - if (std::set{"RespUp", "RespDown", "ResolUp", "ResolDown"}.count(variation)) { - ROOT::Math::PtEtaPhiMVector H = - met - vis_gen_boson; + } else if (method == "Uncertainty") { + if (std::set{"RespUp", "RespDown", "ResolUp", + "ResolDown"} + .count(variation)) { + ROOT::Math::PtEtaPhiMVector H = -met - vis_gen_boson; float dPhi_H = H.Phi() - gen_boson.Phi(); float Hpara = H.Pt() * std::cos(dPhi_H); float Hperp = H.Pt() * std::sin(dPhi_H); - float Hpara_new = RecoilCorr->evaluate({order, nJets, genPt, "Hpara", Hpara, variation}); - float Hperp_new = RecoilCorr->evaluate({order, nJets, genPt, "Hperp", Hperp, variation}); - - float Hpt_new = std::sqrt(Hpara_new*Hpara_new + Hperp_new*Hperp_new); - float Hphi_new = std::atan2(Hperp_new, Hpara_new) + gen_boson.Phi(); - if (Hphi_new > M_PI) Hphi_new -= 2*M_PI; - if (Hphi_new < -M_PI) Hphi_new += 2*M_PI; - ROOT::Math::PtEtaPhiMVector H_new = ROOT::Math::PtEtaPhiMVector(Hpt_new, 0., Hphi_new, 0.); - met_new = - H_new - vis_gen_boson; - } - else { + float Hpara_new = RecoilCorr->evaluate( + {order, nJets, genPt, "Hpara", Hpara, variation}); + float Hperp_new = RecoilCorr->evaluate( + {order, nJets, genPt, "Hperp", Hperp, variation}); + + float Hpt_new = std::sqrt(Hpara_new * Hpara_new + + Hperp_new * Hperp_new); + float Hphi_new = + std::atan2(Hperp_new, Hpara_new) + gen_boson.Phi(); + if (Hphi_new > M_PI) + Hphi_new -= 2 * M_PI; + if (Hphi_new < -M_PI) + Hphi_new += 2 * M_PI; + ROOT::Math::PtEtaPhiMVector H_new = + ROOT::Math::PtEtaPhiMVector(Hpt_new, 0., Hphi_new, + 0.); + met_new = -H_new - vis_gen_boson; + } else { Logger::get("met::RecoilCorrection") - ->error("Variation {} not known. Choose either 'RespUp', 'RespDown', 'ResolUp' or 'ResolDown'", variation); - throw std::runtime_error("Invalid variation for Recoil corrections"); + ->error("Variation {} not known. Choose either " + "'RespUp', 'RespDown', 'ResolUp' or " + "'ResolDown'", + variation); + throw std::runtime_error( + "Invalid variation for Recoil corrections"); } - } - else if (method == "QuantileMapFit") { + } else if (method == "QuantileMapFit") { Logger::get("met::RecoilCorrection") - ->debug("QuantileMapFit method not yet implemented, returning uncorrected MET"); + ->debug("QuantileMapFit method not yet implemented, " + "returning uncorrected MET"); return met; - } - else { + } else { Logger::get("met::RecoilCorrection") - ->error("Method {} not known. Choose either 'Rescaling', 'QuantileMapHist' or 'Uncertainty'", method); - throw std::runtime_error("Invalid method for Recoil corrections"); + ->error( + "Method {} not known. Choose either 'Rescaling', " + "'QuantileMapHist' or 'Uncertainty'", + method); + throw std::runtime_error( + "Invalid method for Recoil corrections"); } - - Logger::get("met::RecoilCorrection")->debug("corrected MET X {} ", met_new.Px()); - Logger::get("met::RecoilCorrection")->debug("corrected MET Y {} ", met_new.Py()); - Logger::get("met::RecoilCorrection")->debug("corrected MET {} ", met_new.Pt()); + + Logger::get("met::RecoilCorrection") + ->debug("corrected MET X {} ", met_new.Px()); + Logger::get("met::RecoilCorrection") + ->debug("corrected MET Y {} ", met_new.Py()); + Logger::get("met::RecoilCorrection") + ->debug("corrected MET {} ", met_new.Pt()); return met_new; } }; @@ -167,7 +213,8 @@ ROOT::RDF::RNode RecoilCorrection( } else { // if we do not apply the recoil corrections, just rename the met // column to the new outputname and dont change anything else - return event::quantity::Rename(df, outputname, p4_met); + return event::quantity::Rename( + df, outputname, p4_met); } } @@ -204,15 +251,17 @@ ROOT::RDF::RNode RecoilCorrection( * analyses of Run2. They are not up to standard with the correctionlib json * format, therefore, to be used with caution. */ -ROOT::RDF::RNode RecoilCorrection( - ROOT::RDF::RNode df, const std::string &outputname, - const std::string &p4_met, const std::string &p4_gen_boson, - const std::string &p4_vis_gen_boson, const std::string &jet_pt, - const std::string &corr_file, const std::string &syst_file, - const bool apply_correction, const bool resolution, const bool response, - const bool shift_up, const bool shift_down, const bool is_Wjets) { +ROOT::RDF::RNode +RecoilCorrection(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &p4_gen_boson, + const std::string &p4_vis_gen_boson, const std::string &jet_pt, + const std::string &corr_file, const std::string &syst_file, + const bool apply_correction, const bool resolution, + const bool response, const bool shift_up, + const bool shift_down, const bool is_Wjets) { if (apply_correction) { - Logger::get("met::RecoilCorrection")->debug("Will run recoil corrections"); + Logger::get("met::RecoilCorrection") + ->debug("Will run recoil corrections"); const auto corrector = new RecoilCorrector(corr_file); const auto systematics = new MetSystematic(syst_file); auto shiftType = MetSystematic::SysShift::Nominal; @@ -245,8 +294,8 @@ ROOT::RDF::RNode RecoilCorrection( float correctedMetX = 0.; float correctedMetY = 0.; ROOT::Math::PtEtaPhiMVector corrected_met; - float genPx = gen_boson.Px(); // generator Z(W) px - float genPy = gen_boson.Py(); // generator Z(W) py + float genPx = gen_boson.Px(); // generator Z(W) px + float genPy = gen_boson.Py(); // generator Z(W) py float visPx = vis_gen_boson.Px(); // visible (generator) Z(W) px float visPy = vis_gen_boson.Py(); // visible (generator) Z(W) py Logger::get("met::RecoilCorrection")->debug("Corrector Inputs"); @@ -257,7 +306,8 @@ ROOT::RDF::RNode RecoilCorrection( Logger::get("met::RecoilCorrection")->debug("visPy {} ", visPy); Logger::get("met::RecoilCorrection")->debug("MetX {} ", MetX); Logger::get("met::RecoilCorrection")->debug("MetY {} ", MetY); - Logger::get("met::RecoilCorrection")->debug("old met {} ", met.Pt()); + Logger::get("met::RecoilCorrection") + ->debug("old met {} ", met.Pt()); corrector->CorrectWithHist(MetX, MetY, genPx, genPy, visPx, visPy, nJets30, correctedMetX, correctedMetY); Logger::get("met::RecoilCorrection") @@ -287,13 +337,14 @@ ROOT::RDF::RNode RecoilCorrection( } else { // if we do not apply the recoil corrections, just rename the met // column to the new outputname and dont change anything else - return event::quantity::Rename(df, outputname, p4_met); + return event::quantity::Rename( + df, outputname, p4_met); } } /** - * @brief This function applies MET \f$\phi\f$ corrections as provided by JME POG - * for Run2 in correction JSON files. + * @brief This function applies MET \f$\phi\f$ corrections as provided by JME + * POG for Run2 in correction JSON files. * * @param df input dataframe * @param outputname name of the new column containing the corrected MET Lorentz @@ -303,20 +354,21 @@ ROOT::RDF::RNode RecoilCorrection( * in the event * @param run name of the column containing the run number * @param corr_file path to the file containing the correction - * @param corr_name name of the correction to be applied, e.g. "metphicorr_pfmet_mc", - * possible options are "puppimet" instead of "pfmet" or "data" instead of "mc" + * @param corr_name name of the correction to be applied, e.g. + * "metphicorr_pfmet_mc", possible options are "puppimet" instead of "pfmet" or + * "data" instead of "mc" * * @return a dataframe with the new column containing the corrected MET Lorentz * vector * - * @note This function is only valid for Run2 data and MC. For Run3 the overloaded - * version of this function should be used. + * @note This function is only valid for Run2 data and MC. For Run3 the + * overloaded version of this function should be used. */ ROOT::RDF::RNode METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &p4_met, const std::string &n_pv, - const std::string &run, const std::string &corr_file, - const std::string &corr_name) { + const std::string &p4_met, const std::string &n_pv, + const std::string &run, const std::string &corr_file, + const std::string &corr_name) { auto evaluator_met_pt = correction::CorrectionSet::from_file(corr_file)->at("pt_" + corr_name); @@ -324,8 +376,8 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, correction::CorrectionSet::from_file(corr_file)->at("phi_" + corr_name); auto xyCorrection = [evaluator_met_pt, evaluator_met_phi]( - const ROOT::Math::PtEtaPhiMVector &met, - const int npv, const UInt_t run) { + const ROOT::Math::PtEtaPhiMVector &met, + const int npv, const UInt_t run) { Logger::get("met::METPhiCorrection") ->debug("before: pt {} phi {}", met.Pt(), met.Phi()); @@ -350,8 +402,8 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief This function applies MET \f$\phi\f$ corrections as provided by JME POG - * for Run3 in correction JSON files. + * @brief This function applies MET \f$\phi\f$ corrections as provided by JME + * POG for Run3 in correction JSON files. * * @param df input dataframe * @param outputname name of the new column containing the corrected MET Lorentz @@ -360,9 +412,10 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, * @param n_pv name of the column containing the number of primary vertices * in the event * @param corr_file path to the file containing the correction - * @param corr_name name of the correction to be applied, e.g. "met_xy_corrections" - * @param met_type type of the MET, possible options are "PuppiMET" and "MET" (for - * PF) + * @param corr_name name of the correction to be applied, e.g. + * "met_xy_corrections" + * @param met_type type of the MET, possible options are "PuppiMET" and "MET" + * (for PF) * @param era data-taking period, possible options are e.g. "2022", "2022EE", * "2023", "2023BPix" * @param is_mc boolean indicating whether the sample is MC or data @@ -374,52 +427,52 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, * @return a dataframe with the new column containing the corrected MET Lorentz * vector * - * @note This function is only valid for Run3 data and MC. For Run2 the overloaded - * version of this function should be used. + * @note This function is only valid for Run3 data and MC. For Run2 the + * overloaded version of this function should be used. */ ROOT::RDF::RNode METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &p4_met, const std::string &n_pv, - const std::string &corr_file, const std::string &corr_name, - const std::string &met_type, const std::string &era, - const bool is_mc, const std::string &stat_variation, - const std::string &pileup_variation) { + const std::string &p4_met, const std::string &n_pv, + const std::string &corr_file, const std::string &corr_name, + const std::string &met_type, const std::string &era, + const bool is_mc, const std::string &stat_variation, + const std::string &pileup_variation) { auto evaluator = correction::CorrectionSet::from_file(corr_file)->at(corr_name); const std::string data_mc_key = is_mc ? "MC" : "DATA"; - const std::string pt_key = stat_variation != "nom" ? - "pt_stat_" + stat_variation : "pt"; - const std::string phi_key = stat_variation != "nom" ? - "phi_stat_" + stat_variation : "phi"; - - auto xyCorrection = [evaluator, met_type, era, data_mc_key, - pt_key, phi_key, pileup_variation]( - const ROOT::Math::PtEtaPhiMVector &met, - const int npv) { - Logger::get("met::METPhiCorrection") - ->debug("before: pt {} phi {}", met.Pt(), met.Phi()); - - double corr_met_pt = evaluator->evaluate( - {pt_key, met_type, era, data_mc_key, pileup_variation, - met.Pt(), met.Phi(), float(npv)}); - double corr_met_phi = evaluator->evaluate( - {phi_key, met_type, era, data_mc_key, pileup_variation, - met.Pt(), met.Phi(), float(npv)}); - - double corr_met_X = corr_met_pt * cos(corr_met_phi); - double corr_met_Y = corr_met_pt * sin(corr_met_phi); - ROOT::Math::PtEtaPhiMVector corr_met; - corr_met.SetPxPyPzE( - corr_met_X, corr_met_Y, 0, - std::sqrt(corr_met_X * corr_met_X + corr_met_Y * corr_met_Y)); - - Logger::get("met::METPhiCorrection") - ->debug("after: pt {} phi {}", corr_met.Pt(), corr_met.Phi()); - - return corr_met; - }; + const std::string pt_key = + stat_variation != "nom" ? "pt_stat_" + stat_variation : "pt"; + const std::string phi_key = + stat_variation != "nom" ? "phi_stat_" + stat_variation : "phi"; + + auto xyCorrection = + [evaluator, met_type, era, data_mc_key, pt_key, phi_key, + pileup_variation](const ROOT::Math::PtEtaPhiMVector &met, + const int npv) { + Logger::get("met::METPhiCorrection") + ->debug("before: pt {} phi {}", met.Pt(), met.Phi()); + + double corr_met_pt = evaluator->evaluate( + {pt_key, met_type, era, data_mc_key, pileup_variation, met.Pt(), + met.Phi(), float(npv)}); + double corr_met_phi = evaluator->evaluate( + {phi_key, met_type, era, data_mc_key, pileup_variation, + met.Pt(), met.Phi(), float(npv)}); + + double corr_met_X = corr_met_pt * cos(corr_met_phi); + double corr_met_Y = corr_met_pt * sin(corr_met_phi); + ROOT::Math::PtEtaPhiMVector corr_met; + corr_met.SetPxPyPzE( + corr_met_X, corr_met_Y, 0, + std::sqrt(corr_met_X * corr_met_X + corr_met_Y * corr_met_Y)); + + Logger::get("met::METPhiCorrection") + ->debug("after: pt {} phi {}", corr_met.Pt(), corr_met.Phi()); + + return corr_met; + }; return df.Define(outputname, xyCorrection, {p4_met, n_pv}); } @@ -430,15 +483,18 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, * This function combines information from both corrected and uncorrected jets * to update the MET vector. It concatenates jet kinematic variables and * electromagnetic fractions, then applies Type-1 corrections by subtracting - * the difference between fully corrected and L1-corrected jet transverse momenta - * for jets passing selection criteria. Only jets with $p_T > 15$ GeV and + * the difference between fully corrected and L1-corrected jet transverse + * momenta for jets passing selection criteria. Only jets with $p_T > 15$ GeV + * and * $\mathrm{EmEF} < 0.9$ are propagated to MET. * * @note To be used for v15 nanoAOD samples to both data and MC. * * @param df input dataframe - * @param outputname name of the new column containing the corrected MET Lorentz vector - * @param raw_met name of the column with the initial/uncorrected MET Lorentz vector + * @param outputname name of the new column containing the corrected MET Lorentz + * vector + * @param raw_met name of the column with the initial/uncorrected MET Lorentz + * vector * @param jet_pt_l1corr name of the column with L1-corrected jet $p_T$'s * @param jet_pt_corr name of the column with fully corrected jet $p_T$'s * @param jet_phi name of the column with jet $\phi$'s @@ -458,67 +514,68 @@ METPhiCorrection(ROOT::RDF::RNode df, const std::string &outputname, * @return a new dataframe with the new MET column */ ROOT::RDF::RNode -Type1Correction(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &raw_met, - const std::string &jet_pt_l1corr, - const std::string &jet_pt_corr, - const std::string &jet_phi, - const std::string &jet_muon_subtr_delta_phi, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &low_pt_jet_phi, - const std::string &low_pt_jet_muon_subtr_delta_phi, - const std::string &low_pt_jet_em_ef) { - - auto correction_lambda = [](const ROOT::Math::PtEtaPhiMVector &raw_met, - const ROOT::RVec &jet_L1_pts, - const ROOT::RVec &jet_corr_pts, - const ROOT::RVec &jet_phis, - const ROOT::RVec &jet_muon_subtr_delta_phis, - const ROOT::RVec &jet_ch_em_efs, - const ROOT::RVec &jet_ne_em_efs, - const ROOT::RVec &low_pt_jet_phis, - const ROOT::RVec &low_pt_jet_muon_subtr_delta_phis, - const ROOT::RVec &low_pt_jet_em_efs) { - - float MetX = raw_met.Px(); - float MetY = raw_met.Py(); - ROOT::Math::PtEtaPhiMVector corrected_met; - - ROOT::RVec phis(jet_corr_pts.size()); - phis = ROOT::VecOps::Concatenate(jet_phis + jet_muon_subtr_delta_phis, low_pt_jet_phis + low_pt_jet_muon_subtr_delta_phis); - - ROOT::RVec jet_em_efs(jet_ch_em_efs.size()); - jet_em_efs = jet_ch_em_efs + jet_ne_em_efs; - ROOT::RVec em_efs(jet_corr_pts.size()); - em_efs = ROOT::VecOps::Concatenate(jet_em_efs, low_pt_jet_em_efs); +Type1Correction(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &raw_met, const std::string &jet_pt_l1corr, + const std::string &jet_pt_corr, const std::string &jet_phi, + const std::string &jet_muon_subtr_delta_phi, + const std::string &jet_ch_em_ef, + const std::string &jet_ne_em_ef, + const std::string &low_pt_jet_phi, + const std::string &low_pt_jet_muon_subtr_delta_phi, + const std::string &low_pt_jet_em_ef) { + + auto correction_lambda = + [](const ROOT::Math::PtEtaPhiMVector &raw_met, + const ROOT::RVec &jet_L1_pts, + const ROOT::RVec &jet_corr_pts, + const ROOT::RVec &jet_phis, + const ROOT::RVec &jet_muon_subtr_delta_phis, + const ROOT::RVec &jet_ch_em_efs, + const ROOT::RVec &jet_ne_em_efs, + const ROOT::RVec &low_pt_jet_phis, + const ROOT::RVec &low_pt_jet_muon_subtr_delta_phis, + const ROOT::RVec &low_pt_jet_em_efs) { + float MetX = raw_met.Px(); + float MetY = raw_met.Py(); + ROOT::Math::PtEtaPhiMVector corrected_met; - for (std::size_t i = 0; i < jet_corr_pts.size(); ++i) { - // --- Type-1 jet selection --- - // only propagate objects above the given pt threshold - if (jet_corr_pts.at(i) > 15.0 && em_efs.at(i) < 0.9) { - // Apply (full โˆ’ L1) to MET - float dpt = (jet_corr_pts.at(i) - jet_L1_pts.at(i)); - MetX -= dpt * std::cos(phis.at(i)); - MetY -= dpt * std::sin(phis.at(i)); + ROOT::RVec phis(jet_corr_pts.size()); + phis = ROOT::VecOps::Concatenate( + jet_phis + jet_muon_subtr_delta_phis, + low_pt_jet_phis + low_pt_jet_muon_subtr_delta_phis); + + ROOT::RVec jet_em_efs(jet_ch_em_efs.size()); + jet_em_efs = jet_ch_em_efs + jet_ne_em_efs; + ROOT::RVec em_efs(jet_corr_pts.size()); + em_efs = ROOT::VecOps::Concatenate(jet_em_efs, low_pt_jet_em_efs); + + for (std::size_t i = 0; i < jet_corr_pts.size(); ++i) { + // --- Type-1 jet selection --- + // only propagate objects above the given pt threshold + if (jet_corr_pts.at(i) > 15.0 && em_efs.at(i) < 0.9) { + // Apply (full โˆ’ L1) to MET + float dpt = (jet_corr_pts.at(i) - jet_L1_pts.at(i)); + MetX -= dpt * std::cos(phis.at(i)); + MetY -= dpt * std::sin(phis.at(i)); + } } - } - corrected_met.SetPxPyPzE(MetX, MetY, 0, - std::sqrt(MetX * MetX + MetY * MetY)); - Logger::get("met::Type1Correction")->debug("old met {}, phi {}", raw_met.Pt(), raw_met.Phi()); - Logger::get("met::Type1Correction") - ->debug("corrected met {}, phi {}", corrected_met.Pt(), corrected_met.Phi()); + corrected_met.SetPxPyPzE(MetX, MetY, 0, + std::sqrt(MetX * MetX + MetY * MetY)); + Logger::get("met::Type1Correction") + ->debug("old met {}, phi {}", raw_met.Pt(), raw_met.Phi()); + Logger::get("met::Type1Correction") + ->debug("corrected met {}, phi {}", corrected_met.Pt(), + corrected_met.Phi()); - return corrected_met; - }; + return corrected_met; + }; - auto df1 = df.Define(outputname, correction_lambda, - {raw_met, jet_pt_l1corr, jet_pt_corr, jet_phi, - jet_muon_subtr_delta_phi, jet_ch_em_ef, jet_ne_em_ef, - low_pt_jet_phi, low_pt_jet_muon_subtr_delta_phi, - low_pt_jet_em_ef}); + auto df1 = df.Define(outputname, correction_lambda, + {raw_met, jet_pt_l1corr, jet_pt_corr, jet_phi, + jet_muon_subtr_delta_phi, jet_ch_em_ef, jet_ne_em_ef, + low_pt_jet_phi, low_pt_jet_muon_subtr_delta_phi, + low_pt_jet_em_ef}); return df1; } @@ -529,15 +586,17 @@ Type1Correction(ROOT::RDF::RNode df, * This function combines information from both corrected and uncorrected jets * to update the MET vector. It concatenates jet kinematic variables and * electromagnetic fractions, then applies Type-1 corrections by subtracting - * the difference between fully corrected and L1-corrected jet transverse momenta - * for jets passing selection criteria. Only jets with $p_T > 15$ GeV and - * $\mathrm{EmEF} < 0.9$ are propagated to MET. + * the difference between fully corrected and L1-corrected jet transverse + * momenta for jets passing selection criteria. Only jets with $p_T > 15$ GeV + * and $\mathrm{EmEF} < 0.9$ are propagated to MET. * * @note To be used for v9/v12 nanoAOD samples to both data and MC. * * @param df input dataframe - * @param outputname name of the new column containing the corrected MET Lorentz vector - * @param raw_met name of the column with the initial/uncorrected MET Lorentz vector + * @param outputname name of the new column containing the corrected MET Lorentz + * vector + * @param raw_met name of the column with the initial/uncorrected MET Lorentz + * vector * @param jet_pt_l1corr name of the column with L1-corrected jet $p_T$'s * @param jet_pt_corr name of the column with fully corrected jet $p_T$'s * @param jet_phi name of the column with jet $\phi$'s @@ -550,15 +609,12 @@ Type1Correction(ROOT::RDF::RNode df, * @return A new DataFrame with the corrected MET column. */ ROOT::RDF::RNode -Type1Correction(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &raw_met, - const std::string &jet_pt_l1corr, - const std::string &jet_pt_corr, - const std::string &jet_phi, - const std::string &jet_ch_em_ef, - const std::string &jet_ne_em_ef, - const std::string &low_pt_jet_phi) { +Type1Correction(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &raw_met, const std::string &jet_pt_l1corr, + const std::string &jet_pt_corr, const std::string &jet_phi, + const std::string &jet_ch_em_ef, + const std::string &jet_ne_em_ef, + const std::string &low_pt_jet_phi) { auto correction_lambda = [](const ROOT::Math::PtEtaPhiMVector &raw_met, const ROOT::RVec &jet_L1_pts, @@ -567,7 +623,6 @@ Type1Correction(ROOT::RDF::RNode df, const ROOT::RVec &jet_ch_em_efs, const ROOT::RVec &jet_ne_em_efs, const ROOT::RVec &low_pt_jet_phis) { - float MetX = raw_met.Px(); float MetY = raw_met.Py(); ROOT::Math::PtEtaPhiMVector corrected_met; @@ -577,7 +632,8 @@ Type1Correction(ROOT::RDF::RNode df, ROOT::RVec jet_em_efs(jet_ch_em_efs.size()); jet_em_efs = jet_ch_em_efs + jet_ne_em_efs; - // Setting low pT jets to 0 to always be true for the EmEF < 0.9 condition + // Setting low pT jets to 0 to always be true for the EmEF < 0.9 + // condition ROOT::RVec low_pt_jet_em_efs(low_pt_jet_phis.size(), 0.0); ROOT::RVec em_efs(jet_corr_pts.size()); em_efs = ROOT::VecOps::Concatenate(jet_em_efs, low_pt_jet_em_efs); @@ -594,17 +650,19 @@ Type1Correction(ROOT::RDF::RNode df, } corrected_met.SetPxPyPzE(MetX, MetY, 0, - std::sqrt(MetX * MetX + MetY * MetY)); - Logger::get("met::Type1Correction")->debug("old met {}, phi {}", raw_met.Pt(), raw_met.Phi()); + std::sqrt(MetX * MetX + MetY * MetY)); + Logger::get("met::Type1Correction") + ->debug("old met {}, phi {}", raw_met.Pt(), raw_met.Phi()); Logger::get("met::Type1Correction") - ->debug("corrected met {}, phi {}", corrected_met.Pt(), corrected_met.Phi()); + ->debug("corrected met {}, phi {}", corrected_met.Pt(), + corrected_met.Phi()); return corrected_met; }; - auto df1 = df.Define(outputname, correction_lambda, - {raw_met, jet_pt_l1corr, jet_pt_corr, jet_phi, - jet_ch_em_ef, jet_ne_em_ef, low_pt_jet_phi}); + auto df1 = df.Define(outputname, correction_lambda, + {raw_met, jet_pt_l1corr, jet_pt_corr, jet_phi, + jet_ch_em_ef, jet_ne_em_ef, low_pt_jet_phi}); return df1; } @@ -614,17 +672,19 @@ namespace physicsobject { /** * @brief This function propagates object corrections to the MET based on - * vectors of physics objects. The objects can be e.g. a collection/vector of jets. - * If the energy of an object is corrected/changed (e.g. via some scale factor) or - * due to a shift, this change in energy has to be propagated to the MET vector, and - * the MET vector has to be adapted accordingly. The MET is recalculated via + * vectors of physics objects. The objects can be e.g. a collection/vector of + * jets. If the energy of an object is corrected/changed (e.g. via some scale + * factor) or due to a shift, this change in energy has to be propagated to the + * MET vector, and the MET vector has to be adapted accordingly. The MET is + * recalculated via * * \f[ * E_{T,miss,x}^{\text{corrected}} = E_{T,miss,x} + p_{x,\text{object}} * - p_{x,\text{object}}^{\text{corrected}} \\ * E_{T,miss,y}^{\text{corrected}} = E_{T,miss,y} + p_{y,\text{object}} * - p_{y,\text{object}}^{\text{corrected}} \\ - * E_{T,miss}^{\text{corrected}} = \sqrt{E_{T,miss,x}^{\text{corrected}} * E_{T,miss,x}^{\text{corrected}} + * E_{T,miss}^{\text{corrected}} = \sqrt{E_{T,miss,x}^{\text{corrected}} * + * E_{T,miss,x}^{\text{corrected}} * + E_{T,miss,y}^{\text{corrected}} * E_{T,miss,y}^{\text{corrected}}} * \f] * @@ -648,33 +708,35 @@ namespace physicsobject { * objects * @param phi name of the column containing \f$\phi\f$ vector of the uncorrected * objects - * @param mass name of the column containing mass vector of the uncorrected objects + * @param mass name of the column containing mass vector of the uncorrected + * objects * @param apply_propagation boolean indicating whether the propagation should be * applied or just the original MET vector should be returned - * @param min_pt minimal \f$p_T\f$, the corrected object has to have in order for - * the MET propagation to be applied + * @param min_pt minimal \f$p_T\f$, the corrected object has to have in order + * for the MET propagation to be applied * * @return a dataframe with the new column containing the corrected MET Lorentz * vector */ -ROOT::RDF::RNode PropagateToMET( - ROOT::RDF::RNode df, const std::string &outputname, const std::string &p4_met, - const std::string &pt_corrected, const std::string &eta_corrected, - const std::string &phi_corrected, const std::string &mass_corrected, - const std::string &pt, const std::string &eta, - const std::string &phi, const std::string &mass, - bool apply_propagation, float min_pt) { +ROOT::RDF::RNode +PropagateToMET(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &p4_met, const std::string &pt_corrected, + const std::string &eta_corrected, + const std::string &phi_corrected, + const std::string &mass_corrected, const std::string &pt, + const std::string &eta, const std::string &phi, + const std::string &mass, bool apply_propagation, float min_pt) { // propagate objects corrections to MET, since we can have an arbitrary // amount of objects, this has to be done per event auto scaleMet = [min_pt](const ROOT::Math::PtEtaPhiMVector &met, - const ROOT::RVec &pts_corrected, - const ROOT::RVec &etas_corrected, - const ROOT::RVec &phis_corrected, - const ROOT::RVec &masses_corrected, - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &phis, - const ROOT::RVec &masses) { + const ROOT::RVec &pts_corrected, + const ROOT::RVec &etas_corrected, + const ROOT::RVec &phis_corrected, + const ROOT::RVec &masses_corrected, + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &phis, + const ROOT::RVec &masses) { ROOT::Math::PtEtaPhiMVector corrected_met; ROOT::Math::PtEtaPhiMVector uncorrected_object; ROOT::Math::PtEtaPhiMVector corrected_object; @@ -705,20 +767,21 @@ ROOT::RDF::RNode PropagateToMET( ->debug("MetX {}, MetY {}", MetX, MetY); corrected_met.SetPxPyPzE(MetX, MetY, 0, std::sqrt(MetX * MetX + MetY * MetY)); - Logger::get("physicsobject::PropagateToMET")->debug("old met {}", met.Pt()); + Logger::get("physicsobject::PropagateToMET") + ->debug("old met {}", met.Pt()); Logger::get("physicsobject::PropagateToMET") ->debug("corrected met {}", corrected_met.Pt()); return corrected_met; }; if (apply_propagation) { return df.Define(outputname, scaleMet, - {p4_met, pt_corrected, eta_corrected, - phi_corrected, mass_corrected, pt, - eta, phi, mass}); + {p4_met, pt_corrected, eta_corrected, phi_corrected, + mass_corrected, pt, eta, phi, mass}); } else { // if we do not apply the propagation, just rename the met column to // the new outputname and dont change anything else - return event::quantity::Rename(df, outputname, p4_met); + return event::quantity::Rename( + df, outputname, p4_met); } } } // end namespace physicsobject diff --git a/src/ml.cxx b/src/ml.cxx index fc3ea684..5d4d44f6 100644 --- a/src/ml.cxx +++ b/src/ml.cxx @@ -14,7 +14,6 @@ #include "TInterpreter.h" #include "TMVA/RModel.hxx" -#include "TMVA/RModelParser_ONNX.hxx" #include "TSystem.h" #include #include @@ -207,4 +206,4 @@ StandardTransformer(ROOT::RDF::RNode df, } } // end namespace ml -#endif /* GUARD_ML_H */ \ No newline at end of file +#endif /* GUARD_ML_H */ diff --git a/src/muons.cxx b/src/muons.cxx index c0b20954..81551827 100644 --- a/src/muons.cxx +++ b/src/muons.cxx @@ -340,8 +340,8 @@ ROOT::RDF::RNode Iso(ROOT::RDF::RNode df, * * @return a new dataframe containing the new column * - * @warning This function is deprecated. Use the overloaded function with the additional - * parameter `trigger_flag` instead. + * @warning This function is deprecated. Use the overloaded function with the + * additional parameter `trigger_flag` instead. */ ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, @@ -423,16 +423,11 @@ Trigger(ROOT::RDF::RNode df, auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); auto df1 = df.Define( outputname, - [evaluator, variation, sf_name](const float &pt, - const float &eta, + [evaluator, variation, sf_name](const float &pt, const float &eta, const bool &trigger_flag) { Logger::get("physicsobject::muon::scalefactor::Trigger") - ->debug( - "Trigger - pt {}, eta {}, trigger flag {}", - pt, - eta, - trigger_flag - ); + ->debug("Trigger - pt {}, eta {}, trigger flag {}", pt, eta, + trigger_flag); double sf = 1.; // check to prevent muons with default values due to tau energy // correction shifts below good tau pt selection diff --git a/src/pairselection.cxx b/src/pairselection.cxx index f165ed98..b03971bf 100644 --- a/src/pairselection.cxx +++ b/src/pairselection.cxx @@ -64,6 +64,7 @@ namespace ditau_pairselection { * reference for the first pair particle * @param genindex_particle2 the column containing the index of the GenParticle * reference for the second pair particle + * * @return a new Dataframe with the GenDiTauPair column */ ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, @@ -73,16 +74,22 @@ ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, const std::string &genindex_particle2) { // In nanoAODv12 the types of gen object indices were changed to Short_t // For v9 compatibility a type casting is applied - auto [df1, genindex_particle1_column] = utility::Cast, ROOT::RVec>( - df, genindex_particle1+"_v12", "ROOT::VecOps::RVec", genindex_particle1); - auto [df2, genindex_particle2_column] = utility::Cast, ROOT::RVec>( - df1, genindex_particle2+"_v12", "ROOT::VecOps::RVec", genindex_particle2); + auto [df1, genindex_particle1_column] = + utility::Cast, ROOT::RVec>( + df, genindex_particle1 + "_v12", "ROOT::VecOps::RVec", + genindex_particle1); + auto [df2, genindex_particle2_column] = + utility::Cast, ROOT::RVec>( + df1, genindex_particle2 + "_v12", "ROOT::VecOps::RVec", + genindex_particle2); auto getGenPair = [](const ROOT::RVec &recopair, const ROOT::RVec &genindex_particle1_v12, const ROOT::RVec &genindex_particle2_v12) { - auto genindex_particle1 = static_cast>(genindex_particle1_v12); - auto genindex_particle2 = static_cast>(genindex_particle2_v12); + auto genindex_particle1 = + static_cast>(genindex_particle1_v12); + auto genindex_particle2 = + static_cast>(genindex_particle2_v12); ROOT::RVec genpair = {-1, -1}; Logger::get("buildgenpair")->debug("existing DiTauPair: {}", recopair); genpair[0] = genindex_particle1.at(recopair.at(0), -1); @@ -91,8 +98,9 @@ ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, ->debug("matching GenDiTauPair: {}", genpair); return genpair; }; - return df2.Define(outputname, getGenPair, - {recopair, genindex_particle1_column, genindex_particle2_column}); + return df2.Define( + outputname, getGenPair, + {recopair, genindex_particle1_column, genindex_particle2_column}); } /** @@ -103,8 +111,8 @@ ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, mother particle. * * @param df the Dataframe - * @param outputname name of the new column containing the index of the two selected gen - particles + * @param outputname name of the new column containing the index of the two + selected gen particles * @param statusflags the column containing the status flags of the gen particles * @param status the column containing the status of the genparticles (status=1 @@ -121,29 +129,28 @@ ROOT::RDF::RNode buildgenpair(ROOT::RDF::RNode df, */ ROOT::RDF::RNode -buildtruegenpair(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &statusflags, - const std::string &status, - const std::string &pdgids, - const std::string &motherids, - const std::string &pts, - const int mother_pdgid, - const int daughter_1_pdgid, - const int daughter_2_pdgid) { - // In nanoAODv12 the type of genparticle status flags / mother index were changed to UShort_t / Short_t - // For v9 compatibility a type casting is applied - auto [df1, statusflags_column] = utility::Cast, ROOT::RVec>( - df, statusflags+"_v12", "ROOT::VecOps::RVec", statusflags); - auto [df2, motherids_column] = utility::Cast, ROOT::RVec>( - df1, motherids+"_v12", "ROOT::VecOps::RVec", motherids); - - auto getTrueGenPair = [mother_pdgid, daughter_1_pdgid, - daughter_2_pdgid](const ROOT::RVec &statusflags_v12, - const ROOT::RVec &status, - const ROOT::RVec &pdgids, - const ROOT::RVec &motherids_v12, - const ROOT::RVec &pts) { +buildtruegenpair(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &statusflags, const std::string &status, + const std::string &pdgids, const std::string &motherids, + const std::string &pts, const int mother_pdgid, + const int daughter_1_pdgid, const int daughter_2_pdgid) { + // In nanoAODv12 the type of genparticle status flags / mother index were + // changed to UShort_t / Short_t. For v9 compatibility a type casting is + // applied. + auto [df1, statusflags_column] = + utility::Cast, ROOT::RVec>( + df, statusflags + "_v12", "ROOT::VecOps::RVec", + statusflags); + auto [df2, motherids_column] = + utility::Cast, ROOT::RVec>( + df1, motherids + "_v12", "ROOT::VecOps::RVec", motherids); + + auto getTrueGenPair = [mother_pdgid, daughter_1_pdgid, daughter_2_pdgid]( + const ROOT::RVec &statusflags_v12, + const ROOT::RVec &status, + const ROOT::RVec &pdgids, + const ROOT::RVec &motherids_v12, + const ROOT::RVec &pts) { auto statusflags = static_cast>(statusflags_v12); auto motherids = static_cast>(motherids_v12); ROOT::RVec genpair = {-1, -1}; @@ -251,8 +258,9 @@ buildtruegenpair(ROOT::RDF::RNode df, return genpair; }; - return df2.Define(outputname, getTrueGenPair, - {statusflags_column, status, pdgids, motherids_column, pts}); + return df2.Define( + outputname, getTrueGenPair, + {statusflags_column, status, pdgids, motherids_column, pts}); } /// This function flags events, where a suitable particle pair is found. /// A pair is considered suitable, if a PairSelectionAlgo (like diff --git a/src/quantities.cxx b/src/quantities.cxx index b06829ba..3aa4324e 100644 --- a/src/quantities.cxx +++ b/src/quantities.cxx @@ -11,19 +11,18 @@ #include #include - namespace quantities { /** - * @brief This function calculates the spatial distance in the x-y-plane + * @brief This function calculates the spatial distance in the x-y-plane * (\f$\Delta\phi\f$) between two Lorentz vectors. * - * @note For the calculation the `ROOT::Math::VectorUtil::DeltaPhi()` - * function is used which already takes care of the periodicity of the + * @note For the calculation the `ROOT::Math::VectorUtil::DeltaPhi()` + * function is used which already takes care of the periodicity of the * azimuthal angle. * * @param df input dataframe - * @param outputname name of the output column containing the \f$\Delta\phi\f$ + * @param outputname name of the output column containing the \f$\Delta\phi\f$ * value * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector @@ -43,14 +42,14 @@ ROOT::RDF::RNode DeltaPhi(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief This function calculates the difference in pseudorapidity + * @brief This function calculates the difference in pseudorapidity * (\f$\Delta\eta\f$) between two Lorentz vectors. * - * @note The calculation is a simple subtraction of the eta components: + * @note The calculation is a simple subtraction of the eta components: * \f$\eta_1 - \eta_2\f$. * * @param df input dataframe - * @param outputname name of the output column containing the \f$\Delta\eta\f$ + * @param outputname name of the output column containing the \f$\Delta\eta\f$ * value * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector @@ -70,15 +69,15 @@ ROOT::RDF::RNode DeltaEta(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief This function calculates the spatial distance in the + * @brief This function calculates the spatial distance in the * \f$\eta\f$-\f$\phi\f$-plane (\f$\Delta R\f$) between two Lorentz vectors. * It is defined as * \f[ \Delta R = \sqrt{(\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2} \f] - * where \f$\eta_1\f$ and \f$\phi_1\f$ are from the first Lorentz vector and \f$\eta_2\f$ - * and \f$\phi_2\f$ are from the second Lorentz vector. + * where \f$\eta_1\f$ and \f$\phi_1\f$ are from the first Lorentz vector and + * \f$\eta_2\f$ and \f$\phi_2\f$ are from the second Lorentz vector. * * @param df input dataframe - * @param outputname name of the output column containing the \f$\Delta R\f$ + * @param outputname name of the output column containing the \f$\Delta R\f$ * value * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector @@ -86,7 +85,8 @@ ROOT::RDF::RNode DeltaEta(ROOT::RDF::RNode df, const std::string &outputname, * @return a new dataframe with the new column */ ROOT::RDF::RNode DeltaR(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2) { + const std::string &vector_1, + const std::string &vector_2) { auto calculate_deltaR = [](ROOT::Math::PtEtaPhiMVector &p4_1, ROOT::Math::PtEtaPhiMVector &p4_2) { if (p4_1.pt() < 0.0 || p4_2.pt() < 0.0) @@ -98,7 +98,7 @@ ROOT::RDF::RNode DeltaR(ROOT::RDF::RNode df, const std::string &outputname, /** * @brief This function checks the hemisphere of a pair of particles. If both - * particles are in the same hemisphere (both positive/negative \f$\eta\f$), + * particles are in the same hemisphere (both positive/negative \f$\eta\f$), * the quantity is set to `1`, otherwise it is set to `0`. * * @param df name of the dataframe @@ -118,34 +118,36 @@ ROOT::RDF::RNode PairHemisphere(ROOT::RDF::RNode df, return default_int; return (int)(p4_1.Eta() * p4_2.Eta() > 0); }; - return df.Define(outputname, calculate_hemisphere, - {vector_1, vector_2}); + return df.Define(outputname, calculate_hemisphere, {vector_1, vector_2}); } /** - * @brief This function calculates the quantity `pZetaMissVis` from the two leptons - * in the event and the MET vector. The variable is defined as: + * @brief This function calculates the quantity `pZetaMissVis` from the two + * leptons in the event and the MET vector. The variable is defined as: * \f[ * D_\zeta = p_\zeta^\text{miss} - 0.85 p_\zeta^\text{vis} * \qquad * p_\zeta^\text{miss} = \vec{p}_\text{T}^\text{miss} \cdot \hat{\zeta} * \qquad - * p_\zeta^\text{vis} = (\vec{p}_\text{T}^{p_1} + \vec{p}_\text{T}^{p_2}) \cdot - * \hat{\zeta} - * \f] - * where \f$\vec{p}_\text{T}^{p_{1,2}}\f$ corresponds to the transverse momentum - * vector of the first (second) lepton and \f$\hat{\zeta}\f$ to the bisectional + * p_\zeta^\text{vis} = (\vec{p}_\text{T}^{p_1} + \vec{p}_\text{T}^{p_2}) + * \cdot + * \hat{\zeta} + * \f] + * where \f$\vec{p}_\text{T}^{p_{1,2}}\f$ corresponds to the transverse momentum + * vector of the first (second) lepton and \f$\hat{\zeta}\f$ to the bisectional * direction between the two leptons in the transverse plane. * - * For more information check: D. Jang, โ€œSearch for MSSM Higgs decaying to tau pairs - * in pp collision at โˆšs=1.96 TeV at CDFโ€. PhD thesis, Rutgers University, 2006. - * FERMILAB-THESIS-2006-11. + * For more information check: D. Jang, โ€œSearch for MSSM Higgs decaying to tau + * pairs in pp collision at โˆšs=1.96 TeV at CDFโ€. PhD thesis, Rutgers University, + * 2006. FERMILAB-THESIS-2006-11. * * @param df the input dataframe - * @param outputname the name of the output column containing the PzetaMissVis value + * @param outputname the name of the output column containing the PzetaMissVis + * value * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector - * @param vector_3 name of the column containing the third Lorentz vector (MET vector) + * @param vector_3 name of the column containing the third Lorentz vector (MET + * vector) * * @return a new dataframe with the new column */ @@ -174,12 +176,14 @@ ROOT::RDF::RNode PzetaMissVis(ROOT::RDF::RNode df, auto pzetaVis = dileptonsystem.Dot(zeta); return met_3dvec.Dot(zeta) - (alpha * pzetaVis); }; - return df.Define(outputname, calculate_pzetamissvis, {vector_1, vector_2, vector_3}); + return df.Define(outputname, calculate_pzetamissvis, + {vector_1, vector_2, vector_3}); } /** - * @brief This function calculates the transverse mass \f$m_T\f$ of a two particle - * system, where both particles are massless. The transverse mass is defined as: + * @brief This function calculates the transverse mass \f$m_T\f$ of a two + * particle system, where both particles are massless. The transverse mass is + * defined as: * * \f[ * m_{T} = \sqrt{2 \cdot p_{T,1} \cdot p_{T,2} \cdot @@ -189,8 +193,8 @@ ROOT::RDF::RNode PzetaMissVis(ROOT::RDF::RNode df, * where \f$\Delta\phi\f$ is the azimuthal angle between the two particles. * * @note The transverse mass is usually used to estimate the mass of the W boson - * based on a lepton (particle 1) and the missing transverse energy as the - * neutrino (particle 2). + * based on a lepton (particle 1) and the missing transverse energy as the + * neutrino (particle 2). * * @param df input dataframe * @param outputname name of the output column containing the \f$m_T\f$ value @@ -199,93 +203,109 @@ ROOT::RDF::RNode PzetaMissVis(ROOT::RDF::RNode df, * * @return a new dataframe with the new column */ -ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2) { +ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2) { auto calculate_MT = [](ROOT::Math::PtEtaPhiMVector &p4_1, ROOT::Math::PtEtaPhiMVector &p4_met) { if (p4_1.pt() < 0.0 || p4_met.pt() < 0.0) return default_float; - return (float)sqrt(2 * p4_1.Pt() * p4_met.Pt() * + return (float)sqrt( + 2 * p4_1.Pt() * p4_met.Pt() * (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_1, p4_met)))); }; return df.Define(outputname, calculate_MT, {vector_1, vector_2}); } /** - * @brief This function calculates the total transverse mass for a dilepton - * system plus MET. This is usually used to estimate the Higgs to \f$\tau\tau\f$ - * decay where multiple neutrinos are involved and estimated via the MET vector. + * @brief This function calculates the total transverse mass for a dilepton + * system plus MET. This is usually used to estimate the Higgs to \f$\tau\tau\f$ + * decay where multiple neutrinos are involved and estimated via the MET vector. * The total transverse mass is defined as: * \f[ * m_{T}^{tot} = \sqrt{m_{T}^2(p_{1},E_{T}^{miss}) + - * m_{T}^2(p_{2},E_{T}^{miss}) + m_{T}^2(p_{1},p_2) } + * m_{T}^2(p_{2},E_{T}^{miss}) + m_{T}^2(p_{1},p_2) } * \f] - * where \f$ m_{T}^2 \f$ is the transverse mass, \f$ p_{1}\f$ and \f$ p_{2}\f$ + * where \f$ m_{T}^2 \f$ is the transverse mass, \f$ p_{1}\f$ and \f$ p_{2}\f$ * are the lepton Lorentz vectors and \f$E_{T}^{miss}\f$ is the missing energy. * * @param df input dataframe - * @param outputname name of the output column containing the total transverse mass + * @param outputname name of the output column containing the total transverse + * mass * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector - * @param vector_3 name of the column containing the third Lorentz vector (usually - * the missing transverse energy vector) + * @param vector_3 name of the column containing the third Lorentz vector + * (usually the missing transverse energy vector) * * @return a new dataframe with the new column */ -ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2, - const std::string &vector_3) { +ROOT::RDF::RNode TransverseMass(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2, + const std::string &vector_3) { auto calculate_mt_tot = [](ROOT::Math::PtEtaPhiMVector &p4_1, ROOT::Math::PtEtaPhiMVector &p4_2, ROOT::Math::PtEtaPhiMVector &p4_met) { - const float mt_1 = sqrt(2 * p4_1.Pt() * p4_met.Pt() * - (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_1, p4_met)))); - const float mt_2 = sqrt(2 * p4_2.Pt() * p4_met.Pt() * - (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_2, p4_met)))); - const float mt_mix = sqrt(2 * p4_1.Pt() * p4_2.Pt() * - (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_1, p4_2)))); + const float mt_1 = + sqrt(2 * p4_1.Pt() * p4_met.Pt() * + (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_1, p4_met)))); + const float mt_2 = + sqrt(2 * p4_2.Pt() * p4_met.Pt() * + (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_2, p4_met)))); + const float mt_mix = + sqrt(2 * p4_1.Pt() * p4_2.Pt() * + (1. - cos(ROOT::Math::VectorUtil::DeltaPhi(p4_1, p4_2)))); return (float)sqrt(mt_1 * mt_1 + mt_2 * mt_2 + mt_mix * mt_mix); }; - return df.Define(outputname, calculate_mt_tot, {vector_1, vector_2, vector_3}); + return df.Define(outputname, calculate_mt_tot, + {vector_1, vector_2, vector_3}); } /** - * @brief This function calculates collinear mass approximation. It is defined through - * two equations, assuming, that neutrinos of \f$\tau\f$ decays fly into the same - * direction as visible decay products: + * @brief This function calculates collinear mass approximation. It is defined + * through two equations, assuming, that neutrinos of \f$\tau\f$ decays fly into + * the same direction as visible decay products: * \f[ - * p(\tau_{i}) = (1 + x_{\tau_{i}^{vis}}) \cdot p(\tau_{i}^{vis}), \qquad i = 1,2 + * p(\tau_{i}) = (1 + x_{\tau_{i}^{vis}}) \cdot p(\tau_{i}^{vis}), \qquad i = + * 1,2 * \f] * where \f$ p(...)\f$ represents the Lorentz vectors of the \f$\tau\f$ leptons - * \f$\tau_{1}\f$ and \f$\tau_{2}\f$. The fractions \f$x_{\tau_{i}^{vis}}\f$ are the - * additional amount of neutrino contributions, relative to the visible decay products. - * This means, the missing transverse energy vector \f$\vec{p}_{T}^{miss}\f$ can be - * computed as follows: + * \f$\tau_{1}\f$ and \f$\tau_{2}\f$. The fractions \f$x_{\tau_{i}^{vis}}\f$ are + * the additional amount of neutrino contributions, relative to the visible + * decay products. This means, the missing transverse energy vector + * \f$\vec{p}_{T}^{miss}\f$ can be computed as follows: * \f[ - * \vec{p}_{T}^{miss} = x_{\tau_{1}^{vis}} \cdot \vec{p}_{T}(\tau_{1}^{vis}) + * \vec{p}_{T}^{miss} = x_{\tau_{1}^{vis}} \cdot \vec{p}_{T}(\tau_{1}^{vis}) * + x_{\tau_{2}^{vis}} \cdot \vec{p}_{T}(\tau_{2}^{vis}) * \f] - * This set of equations in turn allows to determine the values \f$x_{\tau_{i}^{vis}}\f$. - * Example for \f$i=1\f$: + * This set of equations in turn allows to determine the values + * \f$x_{\tau_{i}^{vis}}\f$. Example for \f$i=1\f$: * \f[ - * x_{\tau_{1}^{vis}} = \frac{p_{T}^{miss}}{p_{T}(\tau_{1}^{vis})} \cdot - * \frac{\sin(\phi_{\tau_{2}^{vis}} - \phi_{miss})}{\sin(\phi_{\tau_{2}^{vis}} + * x_{\tau_{1}^{vis}} = \frac{p_{T}^{miss}}{p_{T}(\tau_{1}^{vis})} \cdot + * \frac{\sin(\phi_{\tau_{2}^{vis}} - + * \phi_{miss})}{\sin(\phi_{\tau_{2}^{vis}} * - \phi_{\tau_{1}^{vis}})} * \f] - * The collinear mass approximation is then computed from the sum of the full \f$\tau\f$ - * Lorentz vectors \f$p(\tau_{i})\f$. + * The collinear mass approximation is then computed from the sum of the full + * \f$\tau\f$ Lorentz vectors \f$p(\tau_{i})\f$. * * @param df input dataframe - * @param outputname name of the output column containing the approximanted collinear mass + * @param outputname name of the output column containing the approximanted + * collinear mass * @param vector_1 name of the column containing the first Lorentz vector * @param vector_2 name of the column containing the second Lorentz vector - * @param vector_3 name of the column containing the third Lorentz vector (MET vector) + * @param vector_3 name of the column containing the third Lorentz vector (MET + * vector) * * @return a new dataframe with the new column */ -ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &vector_1, const std::string &vector_2, - const std::string &vector_3) { +ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, + const std::string &outputname, + const std::string &vector_1, + const std::string &vector_2, + const std::string &vector_3) { auto calculate_mtt = [](ROOT::Math::PtEtaPhiMVector &p4_1, ROOT::Math::PtEtaPhiMVector &p4_2, ROOT::Math::PtEtaPhiMVector &p4_met) { @@ -299,28 +319,37 @@ ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, const std::string &outp if (std::fabs(sin(delta_phi)) < 1e-6) return default_float; - const float x_1 = p4_met.Pt() / p4_1.Pt() * sin(p4_2.Phi() - p4_met.Phi()) / sin(delta_phi); - const float x_2 = p4_met.Pt() / p4_2.Pt() * sin(p4_1.Phi() - p4_met.Phi()) / (-sin(delta_phi)); - ROOT::Math::PtEtaPhiMVector coll_lorentz = (1. + x_1) * p4_1 + (1. + x_2) * p4_2; + const float x_1 = p4_met.Pt() / p4_1.Pt() * + sin(p4_2.Phi() - p4_met.Phi()) / sin(delta_phi); + const float x_2 = p4_met.Pt() / p4_2.Pt() * + sin(p4_1.Phi() - p4_met.Phi()) / (-sin(delta_phi)); + ROOT::Math::PtEtaPhiMVector coll_lorentz = + (1. + x_1) * p4_1 + (1. + x_2) * p4_2; return (float)coll_lorentz.mass(); }; return df.Define(outputname, calculate_mtt, {vector_1, vector_2, vector_3}); } /** - * @brief This function calculates the FastMTT Lorentz vector as an estimate - * for H\f$(\tau\tau)\f$ based on the information from both reconstructed + * @brief This function calculates the FastMTT Lorentz vector as an estimate + * for H\f$(\tau\tau)\f$ based on the information from both reconstructed * leptons and the reconstructed MET. The implementation is based on * https://github.com/SVfit/ClassicSVfit/tree/fastMTT_19_02_2019 * * @param df input dataframe - * @param outputname name of the output column containing the FastMtt Lorentz vector + * @param outputname name of the output column containing the FastMtt Lorentz + * vector * @param pt_1 name of the column containing the \f$p_T\f$ of the first particle - * @param pt_2 name of the column containing the \f$p_T\f$ of the second particle - * @param eta_1 name of the column containing the \f$\eta\f$ of the first particle - * @param eta_2 name of the column containing the \f$\eta\f$ of the second particle - * @param phi_1 name of the column containing the \f$\phi\f$ of the first particle - * @param phi_2 name of the column containing the \f$\phi\f$ of the second particle + * @param pt_2 name of the column containing the \f$p_T\f$ of the second + * particle + * @param eta_1 name of the column containing the \f$\eta\f$ of the first + * particle + * @param eta_2 name of the column containing the \f$\eta\f$ of the second + * particle + * @param phi_1 name of the column containing the \f$\phi\f$ of the first + * particle + * @param phi_2 name of the column containing the \f$\phi\f$ of the second + * particle * @param mass_1 name of the column containing the mass of the first particle * @param mass_2 name of the column containing the mass of the second particle * @param met_pt name of the column containing MET \f$p_T\f$ @@ -332,21 +361,21 @@ ROOT::RDF::RNode CollinearApproxMtt(ROOT::RDF::RNode df, const std::string &outp * first particle * @param decay_mode_2 name of the column containing the decay mode of the * second particle - * @param finalstate definition of the di-tau final state decay, supported are "mt", - * "et", "tt", "em" + * @param finalstate definition of the di-tau final state decay, supported are + * "mt", "et", "tt", "em" * * @return a new dataframe with the new column */ ROOT::RDF::RNode FastMtt(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &pt_1, const std::string &pt_2, - const std::string &eta_1, const std::string &eta_2, - const std::string &phi_1, const std::string &phi_2, - const std::string &mass_1, const std::string &mass_2, - const std::string &met_pt, const std::string &met_phi, - const std::string &met_cov_xx, const std::string &met_cov_xy, - const std::string &met_cov_yy, const std::string &decay_mode_1, - const std::string &decay_mode_2, const std::string &finalstate) { + const std::string &pt_1, const std::string &pt_2, + const std::string &eta_1, const std::string &eta_2, + const std::string &phi_1, const std::string &phi_2, + const std::string &mass_1, const std::string &mass_2, + const std::string &met_pt, const std::string &met_phi, + const std::string &met_cov_xx, const std::string &met_cov_xy, + const std::string &met_cov_yy, const std::string &decay_mode_1, + const std::string &decay_mode_2, const std::string &finalstate) { // initialize the FastMTT algorithm auto calculate_fast_mtt = [finalstate](const float &pt_1, const float &pt_2, const float &eta_1, @@ -408,8 +437,8 @@ FastMtt(ROOT::RDF::RNode df, const std::string &outputname, } /** - * @brief This function calculates the deltaPhi between the lepton from a W boson - * and the visible Higgs boson decay products. + * @brief This function calculates the deltaPhi between the lepton from a W + * boson and the visible Higgs boson decay products. * * @param df input dataframe * @param outputname name of the new column containing the deltaR value @@ -429,12 +458,13 @@ ROOT::RDF::RNode deltaPhi_WH(ROOT::RDF::RNode df, const std::string &outputname, auto const dileptonsystem = vector_2 + vector_3; return ROOT::Math::VectorUtil::DeltaPhi(vector_1, dileptonsystem); }; - return df.Define(outputname, calculate_deltaPhi, {vector_1, vector_2, vector_3}); + return df.Define(outputname, calculate_deltaPhi, + {vector_1, vector_2, vector_3}); } /** - * @brief This function estimates the pt of the W boson from the visible lepton - * Lorentz vector, the MET Lorentz vector and the neutrino Lorentz vector + * @brief This function estimates the pt of the W boson from the visible lepton + * Lorentz vector, the MET Lorentz vector and the neutrino Lorentz vector * component from the Higgs system. * * @param df input dataframe diff --git a/src/reweighting.cxx b/src/reweighting.cxx index 35df11fa..f401e00e 100644 --- a/src/reweighting.cxx +++ b/src/reweighting.cxx @@ -10,41 +10,41 @@ #include "correction.h" #include - namespace event { namespace reweighting { /** - * @brief This function is used to correct Monte Carlo (MC) simulations for - * differences in the pileup distribution compared to the one measured in data. - * It retrieves a per-event weight from a correction file based on the true number - * of pileup interactions in an event. + * @brief This function is used to correct Monte Carlo (MC) simulations for + * differences in the pileup distribution compared to the one measured in data. + * It retrieves a per-event weight from a correction file based on the true + * number of pileup interactions in an event. * - * The correction files are provided by the Luminosity POG and more information - * about the pileup reweighting can be found here: + * The correction files are provided by the Luminosity POG and more information + * about the pileup reweighting can be found here: * https://twiki.cern.ch/twiki/bin/view/CMS/PileupJSONFileforData * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * pileup weights file - * @param outputname name of the output column containing the pileup event weight - * @param true_pileup_number name of the column containing the true mean number - * of the poisson distribution for an event from which the number of interactions - * each bunch crossing has been sampled + * @param outputname name of the output column containing the pileup event + * weight + * @param true_pileup_number name of the column containing the true mean number + * of the poisson distribution for an event from which the number of + * interactions each bunch crossing has been sampled * @param corr_file path to the file with the pileup weights - * @param corr_name name of the pileup correction in the file, + * @param corr_name name of the pileup correction in the file, * e.g. "Collisions18_UltraLegacy_goldenJSON" - * @param variation name of the pileup weight variation, options are "nominal", + * @param variation name of the pileup weight variation, options are "nominal", * "up" and "down" * * @return a new dataframe containing the new column */ ROOT::RDF::RNode Pileup(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &true_pileup_number, - const std::string &corr_file, const std::string &corr_name, - const std::string &variation) { + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &true_pileup_number, + const std::string &corr_file, const std::string &corr_name, + const std::string &variation) { auto evaluator = correction_manager.loadCorrection(corr_file, corr_name); auto df1 = df.Define(outputname, [evaluator, variation](const float &pu) { @@ -57,14 +57,15 @@ Pileup(ROOT::RDF::RNode df, } /** - * @brief This function is used to evaluate the parton shower (PS) weight of an event. - * The weights are stored in the nanoAOD files and defined as - * \f$w_{variation}\f$ / \f$w_{nominal}\f$. The nominal weight is already applied, - * therefore, the main use of this function is to get the initial state radiation (ISR) - * and final state radiation (FSR) variations to the nominal PS weight. + * @brief This function is used to evaluate the parton shower (PS) weight of an + * event. The weights are stored in the nanoAOD files and defined as + * \f$w_{variation}\f$ / \f$w_{nominal}\f$. The nominal weight is already + * applied, therefore, the main use of this function is to get the initial state + * radiation (ISR) and final state radiation (FSR) variations to the nominal PS + * weight. * - * Depending on the selected ISR and FSR value, a specific index has to be identified. - * The mapping between the index and the ISR and FSR values is: + * Depending on the selected ISR and FSR value, a specific index has to be + * identified. The mapping between the index and the ISR and FSR values is: * ISR | FSR | index * -----------|------------|--------- * 2.0 | 1.0 | 0 @@ -72,22 +73,24 @@ Pileup(ROOT::RDF::RNode df, * 0.5 | 1.0 | 2 * 1.0 | 0.5 | 3 * - * @note For some simulated samples this mapping might be defined differently, - * therefore, it is advisable to check the documentation of the `PSWeight` + * @note For some simulated samples this mapping might be defined differently, + * therefore, it is advisable to check the documentation of the `PSWeight` * branch in the nanoAOD files of the samples if issues occur. * * @param df input dataframe - * @param outputname name of the output column containing the ISR/FSR event weight - * @param ps_weights name of the column containing the parton shower (ISR/FSR) weights + * @param outputname name of the output column containing the ISR/FSR event + * weight + * @param ps_weights name of the column containing the parton shower (ISR/FSR) + * weights * @param isr value of the ISR variation, possible values are 0.5, 1.0, 2.0 * @param fsr value of the FSR variation, possible values are 0.5, 1.0, 2.0 * * @return a new dataframe containing the new column */ ROOT::RDF::RNode PartonShower(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &ps_weights, - const float isr, const float fsr) { + const std::string &outputname, + const std::string &ps_weights, const float isr, + const float fsr) { // find the index we have to use, first check if the isr and fsr values are // valid, only 0.5, 1.0, 2.0 are allowed std::vector allowed_values = {0.5, 1.0, 2.0}; @@ -103,45 +106,42 @@ ROOT::RDF::RNode PartonShower(ROOT::RDF::RNode df, ->error("Invalid value for fsr: {}", fsr); throw std::runtime_error("Invalid value for fsr"); } - - auto ps_weights_lambda = - [isr, fsr](const ROOT::RVec ps_weights) { - if (isr == 1.0 && fsr == 1.0) { - // if the ISR and FSR are both 1.0, we return the nominal weight - return (float)1.0; - } - // now find the index - std::map, int> index_map; - if (ps_weights.size() == 4) { - index_map = { - {{2.0, 1.0}, 0}, {{1.0, 2.0}, 1}, - {{0.5, 1.0}, 2}, {{1.0, 0.5}, 3} - }; - } else { - Logger::get("event::reweighting::PartonShower") - ->error("Invalid number of PS weights: {}", - ps_weights.size()); - throw std::runtime_error("Invalid number of PS weights"); - } - std::pair variations = {isr, fsr}; - int index = index_map[variations]; - return ps_weights.at(index); - }; - auto df1 = - df.Define(outputname, ps_weights_lambda, {ps_weights}); + + auto ps_weights_lambda = [isr, fsr](const ROOT::RVec ps_weights) { + if (isr == 1.0 && fsr == 1.0) { + // if the ISR and FSR are both 1.0, we return the nominal weight + return (float)1.0; + } + // now find the index + std::map, int> index_map; + if (ps_weights.size() == 4) { + index_map = {{{2.0, 1.0}, 0}, + {{1.0, 2.0}, 1}, + {{0.5, 1.0}, 2}, + {{1.0, 0.5}, 3}}; + } else { + Logger::get("event::reweighting::PartonShower") + ->error("Invalid number of PS weights: {}", ps_weights.size()); + throw std::runtime_error("Invalid number of PS weights"); + } + std::pair variations = {isr, fsr}; + int index = index_map[variations]; + return ps_weights.at(index); + }; + auto df1 = df.Define(outputname, ps_weights_lambda, {ps_weights}); return df1; } /** - * @brief This function is used to evaluate the LHE scale weight of an event. The weights - * are stored in the nanoAOD files and defined as \f$w_{variation}\f$ / \f$w_{nominal}\f$. - * The nominal weight is already applied, therefore, the main use of this function is - * to get the factorization and renormalization scale variations to the nominal scale - * weight. + * @brief This function is used to evaluate the LHE scale weight of an event. + * The weights are stored in the nanoAOD files and defined as + * \f$w_{variation}\f$ / \f$w_{nominal}\f$. The nominal weight is already + * applied, therefore, the main use of this function is to get the factorization + * and renormalization scale variations to the nominal scale weight. * - * Depending on the selected \f$\mu_R\f$ and \f$\mu_F\f$ value, a specific index has - * to be identified. The mapping between the index and the \f$\mu_R\f$ and \f$\mu_F\f$ - * values is: + * Depending on the selected \f$\mu_R\f$ and \f$\mu_F\f$ value, a specific index + * has to be identified. The mapping between the index and the \f$\mu_R\f$ and + * \f$\mu_F\f$ values is: * mu_f | mu_r | index * ------------|-------------|--------- * 0.5 | 0.5 | 0 @@ -154,24 +154,24 @@ ROOT::RDF::RNode PartonShower(ROOT::RDF::RNode df, * 1.0 | 2.0 | 7 (6) * 2.0 | 2.0 | 8 (7) * - * @note For some simulated samples this mapping might be defined differently, - * therefore, it is advisable to check the documentation of the `LHEScaleWeight` + * @note For some simulated samples this mapping might be defined differently, + * therefore, it is advisable to check the documentation of the `LHEScaleWeight` * branch in the nanoAOD files of the samples if issues occur. * * @param df input dataframe - * @param outputname name of the output column containing the LHE scale event weight + * @param outputname name of the output column containing the LHE scale event + * weight * @param lhe_scale_weights name of the column containing the LHE scale weights * @param mu_r value of \f$\mu_R\f$ variation, possible values are 0.5, 1.0, 2.0 * @param mu_f value of \f$\mu_F\f$ variation, possible values are 0.5, 1.0, 2.0 * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_scale_weights, - const float mu_r, const float mu_f) { - // find the index we have to use, first check if the mu_r and mu_f values are - // valid, only 0.5, 1.0, 2.0 are allowed +ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_scale_weights, + const float mu_r, const float mu_f) { + // find the index we have to use, first check if the mu_r and mu_f values + // are valid, only 0.5, 1.0, 2.0 are allowed std::vector allowed_values = {0.5, 1.0, 2.0}; if (std::find(allowed_values.begin(), allowed_values.end(), mu_r) == allowed_values.end()) { @@ -185,26 +185,20 @@ ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, ->error("Invalid value for mu_f: {}", mu_f); throw std::runtime_error("Invalid value for mu_f"); } - + auto lhe_scale_weights_lambda = [mu_r, mu_f](const ROOT::RVec scale_weights) { // now find the index std::map, int> index_map; if (scale_weights.size() == 9) { - index_map = { - {{0.5, 0.5}, 0}, {{1.0, 0.5}, 1}, {{2.0, 0.5}, 2}, - {{0.5, 1.0}, 3}, {{1.0, 1.0}, 4}, {{2.0, 1.0}, 5}, - {{0.5, 2.0}, 6}, {{1.0, 2.0}, 7}, {{2.0, 2.0}, 8} - }; - } - else if (scale_weights.size() == 8) { - index_map = { - {{0.5, 0.5}, 0}, {{1.0, 0.5}, 1}, {{2.0, 0.5}, 2}, - {{0.5, 1.0}, 3}, {{2.0, 1.0}, 4}, {{0.5, 2.0}, 5}, - {{1.0, 2.0}, 6}, {{2.0, 2.0}, 7} - }; - } - else { + index_map = {{{0.5, 0.5}, 0}, {{1.0, 0.5}, 1}, {{2.0, 0.5}, 2}, + {{0.5, 1.0}, 3}, {{1.0, 1.0}, 4}, {{2.0, 1.0}, 5}, + {{0.5, 2.0}, 6}, {{1.0, 2.0}, 7}, {{2.0, 2.0}, 8}}; + } else if (scale_weights.size() == 8) { + index_map = {{{0.5, 0.5}, 0}, {{1.0, 0.5}, 1}, {{2.0, 0.5}, 2}, + {{0.5, 1.0}, 3}, {{2.0, 1.0}, 4}, {{0.5, 2.0}, 5}, + {{1.0, 2.0}, 6}, {{2.0, 2.0}, 7}}; + } else { Logger::get("event::reweighting::LHEscale") ->error("Invalid number of LHE scale weights: {}", scale_weights.size()); @@ -220,30 +214,32 @@ ROOT::RDF::RNode LHEscale(ROOT::RDF::RNode df, } /** - * @brief This function is used to evaluate the LHE PDF weight of an event. The weights - * are stored in the nanoAOD files and defined as \f$w_{variation}\f$ / \f$w_{nominal}\f$. - * The nominal weight is already applied, therefore, the main use of this function is - * to get the variation of the PDF weights to the nominal PDF weight. + * @brief This function is used to evaluate the LHE PDF weight of an event. The + * weights are stored in the nanoAOD files and defined as \f$w_{variation}\f$ / + * \f$w_{nominal}\f$. The nominal weight is already applied, therefore, the main + * use of this function is to get the variation of the PDF weights to the + * nominal PDF weight. * - * The PDF weights consist of 101 weights, where the first weight is the nominal weight - * and the remaining 100 weights correspond to alternative PDF sets. + * The PDF weights consist of 101 weights, where the first weight is the nominal + * weight and the remaining 100 weights correspond to alternative PDF sets. * - * @note The proper procedure is to use each alternative PDF set as an independent - * systematic vatiation. However, in case of this function, a simplified approach is used - * to calculate a single PDF weight variation. The standard deviation of the 100 - * alternative PDF weights is calculated and used to define the up and down variations as - * follows: \f$w_{up/down} = 1 \pm \sqrt{\sum_{i=1}^{100} (w_i - 1)^2}\f$ + * @note The proper procedure is to use each alternative PDF set as an + * independent systematic vatiation. However, in case of this function, a + * simplified approach is used to calculate a single PDF weight variation. The + * standard deviation of the 100 alternative PDF weights is calculated and used + * to define the up and down variations as follows: \f$w_{up/down} = 1 \pm + * \sqrt{\sum_{i=1}^{100} (w_i - 1)^2}\f$ * * @param df input dataframe - * @param outputname name of the output column containing the LHE PDF event weight + * @param outputname name of the output column containing the LHE PDF event + * weight * @param lhe_pdf_weights name of the column containing the LHE PDF weights - * @param variation name of the variation that should be evaluated, possible values - * are "nominal", "up", "down" + * @param variation name of the variation that should be evaluated, possible + * values are "nominal", "up", "down" * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, - const std::string &outputname, +ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, const std::string &outputname, const std::string &lhe_pdf_weights, const std::string &variation) { auto lhe_pdf_weights_lambda = @@ -257,7 +253,7 @@ ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, float sum = 0.0; for (size_t i = 1; i < 101; i++) { float diff = pdf_weights[i] - 1; - sum += diff * diff; + sum += diff * diff; } if (variation == "up") { return (float)(1.0 + std::sqrt(sum)); @@ -266,70 +262,70 @@ ROOT::RDF::RNode LHEpdf(ROOT::RDF::RNode df, } else { Logger::get("event::reweighting::LHEpdf") ->error("Invalid variation: {}", variation); - throw std::runtime_error("Invalid variation for LHE PDF weights"); + throw std::runtime_error( + "Invalid variation for LHE PDF weights"); } } else { Logger::get("event::reweighting::LHEpdf") - ->error("Invalid number of LHE PDF weights: {}", - n_pdfs); + ->error("Invalid number of LHE PDF weights: {}", n_pdfs); throw std::runtime_error("Invalid number of LHE PDF weights"); } }; - auto df1 = - df.Define(outputname, lhe_pdf_weights_lambda, {lhe_pdf_weights}); + auto df1 = df.Define(outputname, lhe_pdf_weights_lambda, {lhe_pdf_weights}); return df1; } /** - * @brief This function is used to evaluate the LHE \f$\alpha_S\f$ weight of an event. - * The weights are stored in the nanoAOD files and defined as - * \f$w_{variation}\f$ / \f$w_{nominal}\f$. The nominal weight is already applied, - * therefore, the main use of this function is to get the variation of the \f$\alpha_S\f$ - * weight to the nominal weight. + * @brief This function is used to evaluate the LHE \f$\alpha_S\f$ weight of an + * event. The weights are stored in the nanoAOD files and defined as + * \f$w_{variation}\f$ / \f$w_{nominal}\f$. The nominal weight is already + * applied, therefore, the main use of this function is to get the variation of + * the \f$\alpha_S\f$ weight to the nominal weight. * - * For some samples the \f$\alpha_S\f$ weight is included in the PDF weights vector. In - * that case the full PDF weights vector is expected to contains 103 entries, where the - * first 101 entries are PDF weights and the last two entries correspond to the up and - * down varied \f$\alpha_S\f$ weight. + * For some samples the \f$\alpha_S\f$ weight is included in the PDF weights + * vector. In that case the full PDF weights vector is expected to contains 103 + * entries, where the first 101 entries are PDF weights and the last two entries + * correspond to the up and down varied \f$\alpha_S\f$ weight. * * @param df input dataframe - * @param outputname name of the output column containing the LHE \f$\alpha_S\f$ event weight - * @param lhe_pdf_weights name of the column containing the LHE \f$\alpha_S\f$ weights (it is - * part of the LHE PDF weights) - * @param variation name of the variation that should be evaluated, possible values - * are "nominal", "up", "down" + * @param outputname name of the output column containing the LHE \f$\alpha_S\f$ + * event weight + * @param lhe_pdf_weights name of the column containing the LHE \f$\alpha_S\f$ + * weights (it is part of the LHE PDF weights) + * @param variation name of the variation that should be evaluated, possible + * values are "nominal", "up", "down" * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode LHEalphaS(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &lhe_pdf_weights, - const std::string &variation) { - auto lhe_alphaS_weights_lambda = - [variation](const ROOT::RVec pdf_weights) { - // the nominal weight is already applied, so we can return 1.0 - if (variation == "nominal") { - return (float)1.0; - } - const int n_pdfs = pdf_weights.size(); - if (n_pdfs == 103) { - if (variation == "down") { - return pdf_weights[101]; - } else if (variation == "up") { - return pdf_weights[102]; - } else { - Logger::get("event::reweighting::LHEalphaS") - ->error("Invalid variation: {}", variation); - throw std::runtime_error("Invalid variation for LHE PDF weights"); - } +ROOT::RDF::RNode LHEalphaS(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &lhe_pdf_weights, + const std::string &variation) { + auto lhe_alphaS_weights_lambda = [variation]( + const ROOT::RVec pdf_weights) { + // the nominal weight is already applied, so we can return 1.0 + if (variation == "nominal") { + return (float)1.0; + } + const int n_pdfs = pdf_weights.size(); + if (n_pdfs == 103) { + if (variation == "down") { + return pdf_weights[101]; + } else if (variation == "up") { + return pdf_weights[102]; } else { Logger::get("event::reweighting::LHEalphaS") - ->debug("LHE PDF weights do not include alphaS uncertainty: {}", - n_pdfs); - return (float)1.0; + ->error("Invalid variation: {}", variation); + throw std::runtime_error( + "Invalid variation for LHE PDF weights"); } - }; + } else { + Logger::get("event::reweighting::LHEalphaS") + ->debug("LHE PDF weights do not include alphaS uncertainty: {}", + n_pdfs); + return (float)1.0; + } + }; auto df1 = df.Define(outputname, lhe_alphaS_weights_lambda, {lhe_pdf_weights}); @@ -338,38 +334,41 @@ ROOT::RDF::RNode LHEalphaS(ROOT::RDF::RNode df, /** * @brief This function is used to calculate an event weight to correct the top - * quark \f$p_T\f$ mismodeling in simulated \f$t\bar{t}\f$ events. The correction - * is provided by the Top POG and in case of this function the calculated weight - * corrects NLO simulation (POWHEG+Pythia8) to data. + * quark \f$p_T\f$ mismodeling in simulated \f$t\bar{t}\f$ events. The + * correction is provided by the Top POG and in case of this function the + * calculated weight corrects NLO simulation (POWHEG+Pythia8) to data. * * For reference: https://twiki.cern.ch/twiki/bin/viewauth/CMS/TopPtReweighting * - * The weight is calculated as \f$w=\sqrt{SF(t)\cdot SF(\bar{t})}\f$ + * The weight is calculated as \f$w=\sqrt{SF(t)\cdot SF(\bar{t})}\f$ * * with \f$SF= \exp(0.0615-0.0005\cdot p_T)\f$ * * @param df input dataframe - * @param outputname name of the output column containing the derived event weight - * @param genparticles_pdg_id name of the column containing the PDG IDs of the generator + * @param outputname name of the output column containing the derived event + * weight + * @param genparticles_pdg_id name of the column containing the PDG IDs of the + * generator particles + * @param genparticles_status_flags name of the column containing the status + * flags of the generator particles, where bit 13 contains the isLastCopy flag + * @param genparticles_pt name of the column containing the pt of the generator * particles - * @param genparticles_status_flags name of the column containing the status flags of the - * generator particles, where bit 13 contains the isLastCopy flag - * @param genparticles_pt name of the column containing the pt of the generator particles * * @return a new dataframe containing the new column * - * @note The Top POG also provides other reweighting functions, e.g. for NNLO to + * @note The Top POG also provides other reweighting functions, e.g. for NNLO to * data or NLO to NNLO which could be preferred depending on the use case. */ -ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, - const std::string &outputname, - const std::string &genparticles_pdg_id, - const std::string &genparticles_status_flags, - const std::string &genparticles_pt) { - // In nanoAODv12 the type of genparticle status flags was changed to UShort_t - // For v9 compatibility a type casting is applied - auto [df1, genparticles_status_flags_column] = utility::Cast, ROOT::RVec>( - df, genparticles_status_flags+"_v12", "ROOT::VecOps::RVec", genparticles_status_flags); +ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, const std::string &outputname, + const std::string &genparticles_pdg_id, + const std::string &genparticles_status_flags, + const std::string &genparticles_pt) { + // In nanoAODv12 the type of genparticle status flags was changed to + // UShort_t. For v9 compatibility a type casting is applied. + auto [df1, genparticles_status_flags_column] = + utility::Cast, ROOT::RVec>( + df, genparticles_status_flags + "_v12", + "ROOT::VecOps::RVec", genparticles_status_flags); auto ttbarreweightlambda = [](const ROOT::RVec pdg_ids, const ROOT::RVec status_flags_v12, @@ -400,16 +399,18 @@ ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, exp(parameter_a + parameter_b * top_pts[1])); }; auto df2 = df1.Define(outputname, ttbarreweightlambda, - {genparticles_pdg_id, genparticles_status_flags_column, genparticles_pt}); + {genparticles_pdg_id, + genparticles_status_flags_column, genparticles_pt}); return df2; } /** - * @brief This function is used to calculate an event weight to correct the Z boson + * @brief This function is used to calculate an event weight to correct the Z + * boson * \f$p_T\f$. These corrections are recommended especially * for LO Drell-Yan samples, where the \f$p_T\f$ and mass of the Z boson are - * mismodeled compared to data. This function is defined for the corrections provided - * by the CMS HLepRare group. More details can be found here: + * mismodeled compared to data. This function is defined for the corrections + * provided by the CMS HLepRare group. More details can be found here: * https://cms-higgs-leprare.docs.cern.ch/htt-common/DY_reweight/ * * @note HLepRare only provides corrections for Run3. For Run2 see @@ -418,65 +419,72 @@ ROOT::RDF::RNode TopPt(ROOT::RDF::RNode df, * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file - * @param outputname name of the output column containing the derived event weight + * @param outputname name of the output column containing the derived event + * weight * @param gen_boson name of the column containing the Lorentz vector of the * generator-level boson * @param corr_file path to the correction file containing the Z boson \f$p_T\f$ * corrections * @param corr_name name of the correction in the json file - * @param order order of the used DY samples: "LO" for madgraph, "NLO" for amcatnlo, - * "NNLO" for powheg + * @param order order of the used DY samples: "LO" for madgraph, "NLO" for + * amcatnlo, "NNLO" for powheg * @param variation name of the variation that should be evaluated, options are * "nom", "up", "down" or "upX", "downX". For "up" and "down" the uncertainty is * defined by the envelope of all provided uncertainty sources in the correction - * file. Otherwise the specific uncertainty source "X" is used (where X is a number - * e.g. 1,2,3,...). + * file. Otherwise the specific uncertainty source "X" is used (where X is a + * number e.g. 1,2,3,...). * * @return a new dataframe containing the new column */ ROOT::RDF::RNode ZBosonPt(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &gen_boson, - const std::string &corr_file, - const std::string &corr_name, - const std::string &order, - const std::string &variation) { + const std::string &outputname, const std::string &gen_boson, + const std::string &corr_file, const std::string &corr_name, + const std::string &order, const std::string &variation) { auto corrDY = correction_manager.loadCorrection(corr_file, corr_name); - auto corrDYunc = correction_manager.loadCorrection(corr_file, corr_name + "_N_uncertainty"); + auto corrDYunc = correction_manager.loadCorrection( + corr_file, corr_name + "_N_uncertainty"); // Get number of uncertainties auto n_unc = corrDYunc->evaluate({order}); // Get weight depending on variation - auto corr = [corrDY, order, variation, n_unc](const ROOT::Math::PtEtaPhiMVector &gen_boson) { + auto corr = [corrDY, order, variation, + n_unc](const ROOT::Math::PtEtaPhiMVector &gen_boson) { float weight = 1.0; if (variation == "up" || variation == "down") { - float weight_nom = corrDY->evaluate({order, (float)gen_boson.Pt(), "nom"}); + float weight_nom = + corrDY->evaluate({order, (float)gen_boson.Pt(), "nom"}); weight = weight_nom; for (int i = 1; i <= n_unc; i++) { - float unc_up = corrDY->evaluate({order, (float)gen_boson.Pt(), "up" + std::to_string(i)}); - float unc_down = corrDY->evaluate({order, (float)gen_boson.Pt(), "down" + std::to_string(i)}); + float unc_up = corrDY->evaluate( + {order, (float)gen_boson.Pt(), "up" + std::to_string(i)}); + float unc_down = corrDY->evaluate( + {order, (float)gen_boson.Pt(), "down" + std::to_string(i)}); - if (variation == "up" && unc_up > weight_nom && unc_up > weight) { + if (variation == "up" && unc_up > weight_nom && + unc_up > weight) { weight = unc_up; - } else if (variation == "up" && unc_down > weight_nom && unc_down > weight) { + } else if (variation == "up" && unc_down > weight_nom && + unc_down > weight) { weight = unc_down; - } else if (variation == "down" && unc_down < weight_nom && unc_down < weight) { + } else if (variation == "down" && unc_down < weight_nom && + unc_down < weight) { weight = unc_down; - } else if (variation == "down" && unc_up < weight_nom && unc_up < weight) { + } else if (variation == "down" && unc_up < weight_nom && + unc_up < weight) { weight = unc_up; } } - } - else if (variation == "nom" || variation.rfind("up") != std::string::npos || - variation.rfind("down") != std::string::npos) { - weight = corrDY->evaluate({order, (float)gen_boson.Pt(), variation}); - } - else { + } else if (variation == "nom" || + variation.rfind("up") != std::string::npos || + variation.rfind("down") != std::string::npos) { + weight = + corrDY->evaluate({order, (float)gen_boson.Pt(), variation}); + } else { Logger::get("event::reweighting::ZBosonPt") ->error("Invalid variation: {}", variation); throw std::runtime_error("Invalid variation for Z boson pT weight"); @@ -488,28 +496,28 @@ ZBosonPt(ROOT::RDF::RNode df, } /** - * @brief This function is used to calculate an event weight based on Z boson - * \f$p_T\f$ and mass corrections. These corrections are recommended especially + * @brief This function is used to calculate an event weight based on Z boson + * \f$p_T\f$ and mass corrections. These corrections are recommended especially * for LO Drell-Yan samples, where the \f$p_T\f$ and mass of the Z boson are - * mismodeled compared to data. + * mismodeled compared to data. * * @warning This function is based on workspaces and functions that were derived - * for the legacy \f$H(\tau\tau)\f$ analysis and therefore not up-to-date anymore - * for UL or Run3. + * for the legacy \f$H(\tau\tau)\f$ analysis and therefore not up-to-date + * anymore for UL or Run3. * * @param df input dataframe - * @param outputname name of the output column containing the derived event weight - * @param gen_boson name of the column containing the Lorentz vector of the + * @param outputname name of the output column containing the derived event + * weight + * @param gen_boson name of the column containing the Lorentz vector of the * generator-level boson - * @param workspace_file path to the file which contains the workspace that should be - * used + * @param workspace_file path to the file which contains the workspace that + * should be used * @param functor_name name of the function in the workspace that should be used * @param argset additional arguments that are needed for the function * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode ZPtMass(ROOT::RDF::RNode df, - const std::string &outputname, +ROOT::RDF::RNode ZPtMass(ROOT::RDF::RNode df, const std::string &outputname, const std::string &gen_boson, const std::string &workspace_file, const std::string &functor_name, @@ -517,16 +525,14 @@ ROOT::RDF::RNode ZPtMass(ROOT::RDF::RNode df, // retrieve pt and mass of gen boson reconstructed with the method used by // recoil corrections; resulting quantities are only for the purpose of this // method - auto df1 = df.Define(gen_boson + "_pt", - [](const ROOT::Math::PtEtaPhiMVector &p4) { - return (float)p4.pt(); - }, - {gen_boson}); - auto df2 = df1.Define(gen_boson + "_mass", - [](const ROOT::Math::PtEtaPhiMVector &p4) { - return (float)p4.mass(); - }, - {gen_boson}); + auto df1 = df.Define( + gen_boson + "_pt", + [](const ROOT::Math::PtEtaPhiMVector &p4) { return (float)p4.pt(); }, + {gen_boson}); + auto df2 = df1.Define( + gen_boson + "_mass", + [](const ROOT::Math::PtEtaPhiMVector &p4) { return (float)p4.mass(); }, + {gen_boson}); // set up workspace Logger::get("event::reweighting::ZPtMass") diff --git a/src/taus.cxx b/src/taus.cxx index 221cf2a0..0174d8e8 100644 --- a/src/taus.cxx +++ b/src/taus.cxx @@ -1,10 +1,10 @@ #ifndef GUARD_TAUS_H #define GUARD_TAUS_H +#include "../include/defaults.hxx" #include "../include/utility/CorrectionManager.hxx" #include "../include/utility/Logger.hxx" #include "../include/utility/utility.hxx" -#include "../include/defaults.hxx" #include "ROOT/RDataFrame.hxx" #include "correction.h" #include @@ -18,7 +18,7 @@ namespace tau { * the correctionlib evaluator, depending on the absolute pseudorapidity, decay * mode, and gen match of the tau. If no criterion for any of the variations is * matched, the nominal shift "nom" is returned. - * + * * @param abs_eta absolute pseudorapidity of the tau * @param decay_mode decay mode of the tau * @param gen_match gen match of the tau @@ -35,23 +35,20 @@ namespace tau { * @param variation_gentau_dm1 variation for genuine tau with decay mode 1 * @param variation_gentau_dm10 variation for genuine tau with decay mode 10 * @param variation_gentau_dm11 variation for genuine tau with decay mode 11 - * + * * @return the variation to use in the correctionlib evaluator */ -std::string get_tes_variation( - const float &abs_eta, - const int &decay_mode, - const int &gen_match, - const std::string &variation_efake_dm0_barrel, - const std::string &variation_efake_dm1_barrel, - const std::string &variation_efake_dm0_endcap, - const std::string &variation_efake_dm1_endcap, - const std::string &variation_mufake, - const std::string &variation_gentau_dm0, - const std::string &variation_gentau_dm1, - const std::string &variation_gentau_dm10, - const std::string &variation_gentau_dm11 -) { +std::string get_tes_variation(const float &abs_eta, const int &decay_mode, + const int &gen_match, + const std::string &variation_efake_dm0_barrel, + const std::string &variation_efake_dm1_barrel, + const std::string &variation_efake_dm0_endcap, + const std::string &variation_efake_dm1_endcap, + const std::string &variation_mufake, + const std::string &variation_gentau_dm0, + const std::string &variation_gentau_dm1, + const std::string &variation_gentau_dm10, + const std::string &variation_gentau_dm11) { // values for pseudorapidity cuts to define barrel and endcap regions const float barrel_end_cut = 1.5; const float endcap_end_cut = 2.5; @@ -93,19 +90,13 @@ std::string get_tes_variation( } else if (decay_mode == 11) { variation = variation_gentau_dm11; } - } // debug information Logger::get("physicsobject::tau::get_tes_variation") - ->debug( - "variation for tau abs eta {}, decaymode {}, gen match {}: " - "variation {}", - abs_eta, - decay_mode, - gen_match, - variation - ); + ->debug("variation for tau abs eta {}, decaymode {}, gen match {}: " + "variation {}", + abs_eta, decay_mode, gen_match, variation); return variation; } @@ -113,17 +104,17 @@ std::string get_tes_variation( /** * @brief This function applies a transverse momentum (\f$p_T\f$) correction to * hadronic taus in MC simulations. - * + * * The correction depends on the physical origin of the tau (electron fake, muon * fake, or genuine tau), the decay mode, the \f$p_T\f$, and the pseudorapidity. - * + * * For Run 3 analyses, the corrections are calculated for different working * points of the `DeepTau` algorithm, regarding the identification against * jets and against electrons. This is not the case for Run 2 analyses. This * function can be used for both Run 2 and Run 3 analyses. For Run 2 analyses, * the values of `id_vs_jet_wp` and `id_vs_ele_wp` can be set to `""` * to obtain the corrections. - * + * * The uncertainty scheme is split into nine different uncertainty sources: * - For electrons faking taus, four uncertainty sources are considered, split * by the decay modes 0 and 1, and by whether the tau is found in the barrel @@ -133,24 +124,35 @@ std::string get_tes_variation( * decay modes 0, 1, 10, and 11. * For each source, the variation can be set individually. The variations can * take the values ``nom``, ``up``, or ``down``. - * + * * The correction procedure is taken from the officially recommendation of the * TauPOG: * * The implementation of this function is based on the TAU POG - * [recommendations for Run 2](https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2) - * and [recommendations for Run 3](https://twiki.cern.ch/twiki/bin/view/CMS/TauIDRecommendationForRun3). - * - * The specification of the correctionlib files used to evaluate the corrections can be found here: - * - [2016preVFP](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2016preVFP_UL_tau.html) - * - [2016postVFP](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2016postVFP_UL_tau.html) - * - [2017](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2017_UL_tau.html) - * - [2018](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2018_UL_tau.html) - * - [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2022_Summer22_tau_DeepTau2018v2p5_2022_preEE.html) - * - [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2022_Summer22EE_tau_DeepTau2018v2p5_2022_postEE.html) - * - [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2023_Summer23_tau_DeepTau2018v2p5_2023_preBPix.html) - * - [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2023_Summer23BPix_tau_DeepTau2018v2p5_2023_postBPix.html) - * + * [recommendations for Run + * 2](https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2) + * and [recommendations for Run + * 3](https://twiki.cern.ch/twiki/bin/view/CMS/TauIDRecommendationForRun3). + * + * The specification of the correctionlib files used to evaluate the corrections + * can be found here: + * - + * [2016preVFP](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2016preVFP_UL_tau.html) + * - + * [2016postVFP](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2016postVFP_UL_tau.html) + * - + * [2017](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2017_UL_tau.html) + * - + * [2018](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2018_UL_tau.html) + * - + * [2022preEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2022_Summer22_tau_DeepTau2018v2p5_2022_preEE.html) + * - + * [2022postEE](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2022_Summer22EE_tau_DeepTau2018v2p5_2022_postEE.html) + * - + * [2023preBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2023_Summer23_tau_DeepTau2018v2p5_2023_preBPix.html) + * - + * [2023postBPix](https://cms-nanoaod-integration.web.cern.ch/commonJSONSFs/summaries/TAU_2023_Summer23BPix_tau_DeepTau2018v2p5_2023_postBPix.html) + * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * correction file @@ -160,31 +162,34 @@ std::string get_tes_variation( * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID - * @param id_vs_jet_wp working point for the identification against jets; set to `""` if the corrections do not depend on this parameter - * @param id_vs_ele_wp working point for the identification against electrons; set to `""` if the corrections do not depend on this parameter - * @param variation_efake_dm0_barrel variation for electron faking a tau for decay mode 0 in the barrel region, + * @param id_vs_jet_wp working point for the identification against jets; set to + * `""` if the corrections do not depend on this parameter + * @param id_vs_ele_wp working point for the identification against electrons; + * set to `""` if the corrections do not depend on this parameter + * @param variation_efake_dm0_barrel variation for electron faking a tau for + * decay mode 0 in the barrel region, options are "nom", "up", "down" + * @param variation_efake_dm1_barrel variation for electron faking a tau for + * decay mode 1 in the barrel region, options are "nom", "up", "down" + * @param variation_efake_dm0_endcap variation for electron faking a tau for + * decay mode 0 in the endcap regionefake_, options are "nom", "up", "down" + * @param variation_efake_dm1_endcap variation for electron faking a tau for + * decay mode 1 in the endcap region, options are "nom", "up", "down" + * @param variation_mufake variation for muon faking a tau, options are "nom", + * "up", "down" + * @param variation_gentau_dm0 variation for genuine tau for decay mode 0, * options are "nom", "up", "down" - * @param variation_efake_dm1_barrel variation for electron faking a tau for decay mode 1 in the barrel region, + * @param variation_gentau_dm1 variation for genuine tau for decay mode 1, * options are "nom", "up", "down" - * @param variation_efake_dm0_endcap variation for electron faking a tau for decay mode 0 in the endcap regionefake_, + * @param variation_gentau_dm10 variation for genuine tau for decay mode 10, * options are "nom", "up", "down" - * @param variation_efake_dm1_endcap variation for electron faking a tau for decay mode 1 in the endcap region, + * @param variation_gentau_dm11 variation for genuine tau for decay mode 11, * options are "nom", "up", "down" - * @param variation_mufake variation for muon faking a tau, options are "nom", "up", "down" - * @param variation_gentau_dm0 variation for genuine tau for decay mode 0, options are "nom", "up", - * "down" - * @param variation_gentau_dm1 variation for genuine tau for decay mode 1, options are "nom", "up", - * "down" - * @param variation_gentau_dm10 variation for genuine tau for decay mode 10, options are "nom", "up", - * "down" - * @param variation_gentau_dm11 variation for genuine tau for decay mode 11, options are "nom", "up", - * "down" - * + * * @return a dataframe containing the corrected transverse momenta * * @note This function is intended to be used for Run 3 analyses. In Run 3, @@ -193,146 +198,104 @@ std::string get_tes_variation( * exists for this purpose. */ ROOT::RDF::RNode -PtCorrectionMC( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, - const std::string &eta, - const std::string &decay_mode, - const std::string &gen_match, - const std::string &es_file, - const std::string &correction_name, - const std::string &id_algorithm, - const std::string &variation_efake_dm0_barrel, - const std::string &variation_efake_dm1_barrel, - const std::string &variation_efake_dm0_endcap, - const std::string &variation_efake_dm1_endcap, - const std::string &variation_mufake, - const std::string &variation_gentau_dm0, - const std::string &variation_gentau_dm1, - const std::string &variation_gentau_dm10, - const std::string &variation_gentau_dm11, - const std::string &id_vs_jet_wp = "", - const std::string &id_vs_ele_wp = "" -) { +PtCorrectionMC(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &eta, const std::string &decay_mode, + const std::string &gen_match, const std::string &es_file, + const std::string &correction_name, + const std::string &id_algorithm, + const std::string &variation_efake_dm0_barrel, + const std::string &variation_efake_dm1_barrel, + const std::string &variation_efake_dm0_endcap, + const std::string &variation_efake_dm1_endcap, + const std::string &variation_mufake, + const std::string &variation_gentau_dm0, + const std::string &variation_gentau_dm1, + const std::string &variation_gentau_dm10, + const std::string &variation_gentau_dm11, + const std::string &id_vs_jet_wp = "", + const std::string &id_vs_ele_wp = "") { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); - auto correction_lambda = - [ - evaluator, - id_algorithm, - id_vs_jet_wp, - id_vs_ele_wp, - variation_efake_dm0_barrel, - variation_efake_dm1_barrel, - variation_efake_dm0_endcap, - variation_efake_dm1_endcap, - variation_mufake, - variation_gentau_dm0, - variation_gentau_dm1, - variation_gentau_dm10, - variation_gentau_dm11 - ] ( - const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &decay_modes_v12, - const ROOT::RVec &gen_matches_char - ) { - // convert decay modes and gen matches to integers - auto decay_modes = static_cast>(decay_modes_v12); - auto gen_matches = static_cast>(gen_matches_char); + auto correction_lambda = [evaluator, id_algorithm, id_vs_jet_wp, + id_vs_ele_wp, variation_efake_dm0_barrel, + variation_efake_dm1_barrel, + variation_efake_dm0_endcap, + variation_efake_dm1_endcap, variation_mufake, + variation_gentau_dm0, variation_gentau_dm1, + variation_gentau_dm10, variation_gentau_dm11]( + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &decay_modes_v12, + const ROOT::RVec &gen_matches_char) { + // convert decay modes and gen matches to integers + auto decay_modes = static_cast>(decay_modes_v12); + auto gen_matches = static_cast>(gen_matches_char); - // container for corrected pts - ROOT::RVec corrected_pts(pts.size()); + // container for corrected pts + ROOT::RVec corrected_pts(pts.size()); - for (int i = 0; i < pts.size(); i++) { - // get tau variables that we need for scale factor evaluation - auto pt = pts.at(i); - auto abs_eta = etas.at(i); - auto decay_mode = decay_modes.at(i); - auto gen_match = gen_matches.at(i); - - // set the variation depending on the gen match, decay mode, and barrel/endcap region - std::string variation = get_tes_variation( - abs_eta, - decay_mode, - gen_match, - variation_efake_dm0_barrel, - variation_efake_dm1_barrel, - variation_efake_dm0_endcap, - variation_efake_dm1_endcap, - variation_mufake, - variation_gentau_dm0, - variation_gentau_dm1, - variation_gentau_dm10, - variation_gentau_dm11 - ); - - // evaluate the correction factor - // ensure that the tau fulfills the selection criteria for application of the correction, - // set the correction factor to 1 otherwise - float correction_factor = 1.0; - const std::unordered_set valid_modes = {0, 1, 10, 11}; - if (valid_modes.count(decay_mode)) { - if ((id_vs_jet_wp == "") && (id_vs_ele_wp == "")) { - correction_factor = evaluator->evaluate( - { - pt, - abs_eta, - decay_mode, - gen_match, - id_algorithm, - variation - } - ); - } else { - correction_factor = evaluator->evaluate( - { - pt, - abs_eta, - decay_mode, - gen_match, - id_algorithm, - id_vs_jet_wp, - id_vs_ele_wp, - variation - } - ); - } + for (int i = 0; i < pts.size(); i++) { + // get tau variables that we need for scale factor evaluation + auto pt = pts.at(i); + auto abs_eta = etas.at(i); + auto decay_mode = decay_modes.at(i); + auto gen_match = gen_matches.at(i); + + // set the variation depending on the gen match, decay mode, and + // barrel/endcap region + std::string variation = get_tes_variation( + abs_eta, decay_mode, gen_match, variation_efake_dm0_barrel, + variation_efake_dm1_barrel, variation_efake_dm0_endcap, + variation_efake_dm1_endcap, variation_mufake, + variation_gentau_dm0, variation_gentau_dm1, + variation_gentau_dm10, variation_gentau_dm11); + + // evaluate the correction factor + // ensure that the tau fulfills the selection criteria for + // application of the correction, set the correction factor to 1 + // otherwise + float correction_factor = 1.0; + const std::unordered_set valid_modes = {0, 1, 10, 11}; + if (valid_modes.count(decay_mode)) { + if ((id_vs_jet_wp == "") && (id_vs_ele_wp == "")) { + correction_factor = + evaluator->evaluate({pt, abs_eta, decay_mode, gen_match, + id_algorithm, variation}); } else { - correction_factor = 1.0; + correction_factor = evaluator->evaluate( + {pt, abs_eta, decay_mode, gen_match, id_algorithm, + id_vs_jet_wp, id_vs_ele_wp, variation}); } + } else { + correction_factor = 1.0; + } - // calculate the corrected pt - corrected_pts[i] = pt * correction_factor; + // calculate the corrected pt + corrected_pts[i] = pt * correction_factor; - // debug information - Logger::get("physicsobject::tau::PtCorrectionMC") - ->debug( - "apply tau pt correction to tau pt {}, decaymode {}, " + // debug information + Logger::get("physicsobject::tau::PtCorrectionMC") + ->debug("apply tau pt correction to tau pt {}, decaymode {}, " "gen match {}, variation {} --> corrected pt {}, " "correction factor {}", - pt, - decay_mode, - gen_match, - variation, - corrected_pts.at(i), - correction_factor - ); - } + pt, decay_mode, gen_match, variation, + corrected_pts.at(i), correction_factor); + } - return corrected_pts; - }; + return corrected_pts; + }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } @@ -343,7 +306,7 @@ PtCorrectionMC( * two tau decay modes (dm0 and dm1) and depends on the barrel and endcap region * of the detector. This configuration corresponds to the officially provided * scale factors in Run 2. - * + * * The correction procedure is taken from the officially recommendation of the * TauPOG: * @@ -370,8 +333,8 @@ PtCorrectionMC( * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -390,7 +353,7 @@ PtCorrectionMC( * originating from prompt electrons (`gen_match=1`) and electrons that decayed * from a tau lepton * (`gem_match=3`). - * + * * @note This function is intended to be used for Run 2 analyses. In Run 3, * the tau energy scale corrections also depend on the DeepTau working points * for ID vs. electrons and vs. jets. Use @@ -410,8 +373,9 @@ PtCorrectionMC_eleFake(ROOT::RDF::RNode df, const std::string &variation_dm1_endcap) { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); @@ -472,7 +436,7 @@ PtCorrectionMC_eleFake(ROOT::RDF::RNode df, return corrected_pts; }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } @@ -508,8 +472,8 @@ PtCorrectionMC_eleFake(ROOT::RDF::RNode df, * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -523,7 +487,7 @@ PtCorrectionMC_eleFake(ROOT::RDF::RNode df, * * @note This function is intended to be used for Run 2 analyses. In Run 3, * the tau energy scale corrections also depend on the DeepTau working points - * for ID vs. electrons and vs. jets. Use + * for ID vs. electrons and vs. jets. Use * `physicsobject::tau::TauCorrectionMC` instead. */ ROOT::RDF::RNode @@ -537,8 +501,9 @@ PtCorrectionMC_muFake(ROOT::RDF::RNode df, const std::string &variation) { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); @@ -554,8 +519,7 @@ PtCorrectionMC_muFake(ROOT::RDF::RNode df, if (gen_matches.at(i) == 2 || gen_matches.at(i) == 4) { auto correction_factor = evaluator->evaluate( {pts.at(i), std::abs(etas.at(i)), decay_modes.at(i), - gen_matches.at(i), id_algorithm, - variation}); + gen_matches.at(i), id_algorithm, variation}); corrected_pts[i] = pts.at(i) * correction_factor; } else { corrected_pts[i] = pts.at(i); @@ -567,7 +531,7 @@ PtCorrectionMC_muFake(ROOT::RDF::RNode df, return corrected_pts; }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } @@ -581,7 +545,8 @@ PtCorrectionMC_muFake(ROOT::RDF::RNode df, * The correction procedure is taken from the officially recommendation of the * TauPOG: * - * Run2 (UL): https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 + * Run2 (UL): + * https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -592,8 +557,8 @@ PtCorrectionMC_muFake(ROOT::RDF::RNode df, * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -623,8 +588,9 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &variation_dm10, const std::string &variation_dm11) { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); @@ -642,53 +608,52 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( if (decay_modes.at(i) == 0) { auto correction_factor = evaluator->evaluate( {pts.at(i), std::abs(etas.at(i)), decay_modes.at(i), - gen_matches.at(i), id_algorithm, - variation_dm0}); + gen_matches.at(i), id_algorithm, variation_dm0}); corrected_pts[i] = pts.at(i) * correction_factor; } else if (decay_modes.at(i) == 1) { auto correction_factor = evaluator->evaluate( {pts.at(i), std::abs(etas.at(i)), decay_modes.at(i), - gen_matches.at(i), id_algorithm, - variation_dm1}); + gen_matches.at(i), id_algorithm, variation_dm1}); corrected_pts[i] = pts.at(i) * correction_factor; } else if (decay_modes.at(i) == 10) { auto correction_factor = evaluator->evaluate( {pts.at(i), std::abs(etas.at(i)), decay_modes.at(i), - gen_matches.at(i), id_algorithm, - variation_dm10}); + gen_matches.at(i), id_algorithm, variation_dm10}); corrected_pts[i] = pts.at(i) * correction_factor; } else if (decay_modes.at(i) == 11) { auto correction_factor = evaluator->evaluate( {pts.at(i), std::abs(etas.at(i)), decay_modes.at(i), - gen_matches.at(i), id_algorithm, - variation_dm11}); + gen_matches.at(i), id_algorithm, variation_dm11}); corrected_pts[i] = pts.at(i) * correction_factor; } } else { corrected_pts[i] = pts.at(i); } Logger::get("physicsobject::tau::PtCorrection_genuineTau") - ->debug("tau pt before {}, tau pt after {}, decaymode {}, gen match {}", - pts.at(i), corrected_pts.at(i), decay_modes.at(i), gen_matches.at(i)); + ->debug("tau pt before {}, tau pt after {}, decaymode {}, " + "gen match {}", + pts.at(i), corrected_pts.at(i), decay_modes.at(i), + gen_matches.at(i)); } return corrected_pts; }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } /** * @brief This function corrects the transverse momentum (\f$p_T\f$) in MC * simulations of genuine hadronic taus. The energy scale correction for these - * objects is measured for four tau decay modes (dm0, dm1, dm10 and dm11) and + * objects is measured for four tau decay modes (dm0, dm1, dm10 and dm11) and * in two (\f$p_T\f$) bins of the hadronic tau. This correction is only applied * to genuine hadronic taus (`gen_match=5`). * * The correction procedure is taken from the officially recommendation of the * TauPOG: * - * Run2 (UL): https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 + * Run2 (UL): + * https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 * * @param df input dataframe * @param correction_manager correction manager responsible for loading the @@ -699,8 +664,8 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -734,76 +699,86 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &eta, const std::string &decay_mode, const std::string &gen_match, const std::string &es_file, const std::string &correction_name, const std::string &id_algorithm, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf) { + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf) { const std::unordered_map> variations = { - {0, {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, - {1, {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, - {10, {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, - {11, {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, + {0, + {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, + {1, + {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, + {10, + {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, + {11, + {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, }; // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); - auto evaluator = correction_manager.loadCorrection(es_file, correction_name); + auto evaluator = + correction_manager.loadCorrection(es_file, correction_name); - auto correction_lambda = - [evaluator, id_algorithm, variations](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &decay_modes_v12, - const ROOT::RVec &gen_matches_char) { - - auto decay_modes = static_cast>(decay_modes_v12); - auto gen_matches = static_cast>(gen_matches_char); - ROOT::RVec corrected_pts(pts.size()); - - for (size_t i = 0; i < pts.size(); i++) { - float current_pt = pts.at(i); - int current_dm = decay_modes.at(i); - int current_gen_match = gen_matches.at(i); - - // Default: No correction - corrected_pts[i] = current_pt; - std::string variation = "nom"; - - // Only correct if GenMatch is 5 (Genuine Tau) - if (current_gen_match == 5) { - // Look for DM in our allowed map - auto dm_it = variations.find(current_dm); - - // Only call evaluate if DM is supported (0, 1, 10, 11) - if (dm_it != variations.end()) { - const auto &pt_map = dm_it->second; - - // Determine variation based on pT - auto pt_it = pt_map.upper_bound(current_pt); - if (pt_it != pt_map.begin()) { - variation = std::prev(pt_it)->second; - } + auto correction_lambda = [evaluator, id_algorithm, variations]( + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &decay_modes_v12, + const ROOT::RVec &gen_matches_char) { + auto decay_modes = static_cast>(decay_modes_v12); + auto gen_matches = static_cast>(gen_matches_char); + ROOT::RVec corrected_pts(pts.size()); - auto correction_factor = evaluator->evaluate( - {current_pt, std::abs(etas.at(i)), current_dm, - current_gen_match, id_algorithm, variation}); - - corrected_pts[i] = current_pt * correction_factor; + for (size_t i = 0; i < pts.size(); i++) { + float current_pt = pts.at(i); + int current_dm = decay_modes.at(i); + int current_gen_match = gen_matches.at(i); + + // Default: No correction + corrected_pts[i] = current_pt; + std::string variation = "nom"; + + // Only correct if GenMatch is 5 (Genuine Tau) + if (current_gen_match == 5) { + // Look for DM in our allowed map + auto dm_it = variations.find(current_dm); + + // Only call evaluate if DM is supported (0, 1, 10, 11) + if (dm_it != variations.end()) { + const auto &pt_map = dm_it->second; + + // Determine variation based on pT + auto pt_it = pt_map.upper_bound(current_pt); + if (pt_it != pt_map.begin()) { + variation = std::prev(pt_it)->second; } - } - Logger::get("physicsobject::tau::PtCorrectionMC_genuineTau") - ->debug("tau pt before {}, tau pt after {}, decay mode {}, variation {}", - current_pt, corrected_pts.at(i), current_dm, variation); + auto correction_factor = evaluator->evaluate( + {current_pt, std::abs(etas.at(i)), current_dm, + current_gen_match, id_algorithm, variation}); + + corrected_pts[i] = current_pt * correction_factor; + } } - return corrected_pts; - }; + + Logger::get("physicsobject::tau::PtCorrectionMC_genuineTau") + ->debug("tau pt before {}, tau pt after {}, decay mode {}, " + "variation {}", + current_pt, corrected_pts.at(i), current_dm, variation); + } + return corrected_pts; + }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } @@ -817,7 +792,8 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( * The correction procedure is taken from the officially recommendation of the * TauPOG: * - * Run2 (UL): https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 + * Run2 (UL): + * https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 * * Run3: https://twiki.cern.ch/twiki/bin/view/CMS/TauIDRecommendationForRun3 * @@ -830,8 +806,8 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -864,17 +840,18 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &variation_dm10, const std::string &variation_dm11) { // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); auto correction_lambda = - [evaluator, id_algorithm, wp, vsele_wp, variation_dm0, variation_dm1, variation_dm10, - variation_dm11](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &decay_modes_v12, - const ROOT::RVec &gen_matches_char) { + [evaluator, id_algorithm, wp, vsele_wp, variation_dm0, variation_dm1, + variation_dm10, variation_dm11]( + const ROOT::RVec &pts, const ROOT::RVec &etas, + const ROOT::RVec &decay_modes_v12, + const ROOT::RVec &gen_matches_char) { auto decay_modes = static_cast>(decay_modes_v12); auto gen_matches = static_cast>(gen_matches_char); ROOT::RVec corrected_pts(pts.size()); @@ -915,21 +892,22 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( return corrected_pts; }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } /** * @brief This function corrects the transverse momentum (\f$p_T\f$) in MC * simulations of genuine hadronic taus. The energy scale correction for these - * objects is measured for four tau decay modes (dm0, dm1, dm10 and dm11) and + * objects is measured for four tau decay modes (dm0, dm1, dm10 and dm11) and * in two (\f$p_T\f$) bins of the hadronic tau. This correction is only applied * to genuine hadronic taus (`gen_match=5`). * * The correction procedure is taken from the officially recommendation of the * TauPOG: * - * Run2 (UL): https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 + * Run2 (UL): + * https://twiki.cern.ch/twiki/bin/viewauth/CMS/TauIDRecommendationForRun2 * * Run3: https://twiki.cern.ch/twiki/bin/view/CMS/TauIDRecommendationForRun3 * @@ -942,8 +920,8 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( * @param eta name of the column containing hadronic tau eta values * @param decay_mode name of the column containing hadronic tau decay modes * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param es_file path to the correction file for the energy scale correction * @param correction_name name of the correction in `es_file` * @param id_algorithm identification algorithm used for hadronic tau ID @@ -980,172 +958,185 @@ ROOT::RDF::RNode PtCorrectionMC_genuineTau( const std::string &gen_match, const std::string &es_file, const std::string &correction_name, const std::string &id_algorithm, const std::string &wp, const std::string &vsele_wp, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf) { - + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf) { + const std::unordered_map> variations = { - {0, {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, - {1, {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, - {10, {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, - {11, {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, + {0, + {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, + {1, + {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, + {10, + {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, + {11, + {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, }; // In nanoAODv12 the type of tau decay mode was changed to UChar_t // For v9 compatibility a type casting is applied - auto [df1, decay_mode_column] = utility::Cast, ROOT::RVec>( - df, decay_mode+"_v12", "ROOT::VecOps::RVec", decay_mode); + auto [df1, decay_mode_column] = + utility::Cast, ROOT::RVec>( + df, decay_mode + "_v12", "ROOT::VecOps::RVec", decay_mode); auto evaluator = correction_manager.loadCorrection(es_file, correction_name); - auto correction_lambda = - [evaluator, id_algorithm, wp, vsele_wp, variations](const ROOT::RVec &pts, - const ROOT::RVec &etas, - const ROOT::RVec &decay_modes_v12, - const ROOT::RVec &gen_matches_char) { - auto decay_modes = static_cast>(decay_modes_v12); - auto gen_matches = static_cast>(gen_matches_char); - ROOT::RVec corrected_pts(pts.size()); - for (int i = 0; i < pts.size(); i++) { - float current_pt = pts.at(i); - int current_dm = decay_modes.at(i); - int current_gen_match = gen_matches.at(i); - - // Default: No correction - corrected_pts[i] = current_pt; - std::string variation = "nom"; - - // Only correct if GenMatch is 5 (Genuine Tau) - if (current_gen_match == 5) { - // Look for DM in our allowed map - auto dm_it = variations.find(current_dm); - - // Only call evaluate if DM is supported (0, 1, 10, 11) - if (dm_it != variations.end()) { - const auto &pt_map = dm_it->second; - - // Determine variation based on pT - auto pt_it = pt_map.upper_bound(current_pt); - if (pt_it != pt_map.begin()) { - variation = std::prev(pt_it)->second; - } - - auto correction_factor = evaluator->evaluate( - {current_pt, std::abs(etas.at(i)), current_dm, - current_gen_match, id_algorithm, wp, vsele_wp, - variation}); - - corrected_pts[i] = current_pt * correction_factor; + auto correction_lambda = [evaluator, id_algorithm, wp, vsele_wp, + variations]( + const ROOT::RVec &pts, + const ROOT::RVec &etas, + const ROOT::RVec &decay_modes_v12, + const ROOT::RVec &gen_matches_char) { + auto decay_modes = static_cast>(decay_modes_v12); + auto gen_matches = static_cast>(gen_matches_char); + ROOT::RVec corrected_pts(pts.size()); + for (int i = 0; i < pts.size(); i++) { + float current_pt = pts.at(i); + int current_dm = decay_modes.at(i); + int current_gen_match = gen_matches.at(i); + + // Default: No correction + corrected_pts[i] = current_pt; + std::string variation = "nom"; + + // Only correct if GenMatch is 5 (Genuine Tau) + if (current_gen_match == 5) { + // Look for DM in our allowed map + auto dm_it = variations.find(current_dm); + + // Only call evaluate if DM is supported (0, 1, 10, 11) + if (dm_it != variations.end()) { + const auto &pt_map = dm_it->second; + + // Determine variation based on pT + auto pt_it = pt_map.upper_bound(current_pt); + if (pt_it != pt_map.begin()) { + variation = std::prev(pt_it)->second; } + + auto correction_factor = evaluator->evaluate( + {current_pt, std::abs(etas.at(i)), current_dm, + current_gen_match, id_algorithm, wp, vsele_wp, + variation}); + + corrected_pts[i] = current_pt * correction_factor; } - Logger::get("physicsobject::tau::PtCorrectionMC_genuineTau") - ->debug("tau pt before {}, tau pt after {}, decay mode {}, variation {}", - current_pt, corrected_pts.at(i), current_dm, variation); } - return corrected_pts; - }; + Logger::get("physicsobject::tau::PtCorrectionMC_genuineTau") + ->debug("tau pt before {}, tau pt after {}, decay mode {}, " + "variation {}", + current_pt, corrected_pts.at(i), current_dm, variation); + } + return corrected_pts; + }; auto df2 = df1.Define(outputname, correction_lambda, - {pt, eta, decay_mode_column, gen_match}); + {pt, eta, decay_mode_column, gen_match}); return df2; } namespace quantity { /** - * @brief This function writes out a flag that is true if a tau passes a specific - * tau ID working point (`wp`). The working point is defined by the bit value. The - * bit values can be found e.g. in the description of the tau ID scale factors. - * - * @note This function should be used only for `nanoAODv9`. Starting with `nanoAODv12` - * `physicsobject::tau::quantity::IDFlag_v12` should be used instead because the content - * of the tau ID branches was changed. - * + * @brief This function writes out a flag that is true if a tau passes a + * specific tau ID working point (`wp`). The working point is defined by the bit + * value. The bit values can be found e.g. in the description of the tau ID + * scale factors. + * + * @note This function should be used only for `nanoAODv9`. Starting with + * `nanoAODv12` `physicsobject::tau::quantity::IDFlag_v12` should be used + * instead because the content of the tau ID branches was changed. + * * @param df input dataframe * @param outputname name of the output column containing the flag - * @param ID name of the column containing the tau ID values - * @param index_vector name of the column containing the vector with the relevant - * tau pair indices + * @param ID name of the column containing the tau ID values + * @param index_vector name of the column containing the vector with the + * relevant tau pair indices * @param position position in the index vector of the relevant tau in the pair * @param wp bit value of the WP that has to be passed * * @return a new dataframe containing the new column */ ROOT::RDF::RNode IDFlag_v9(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &ID, const std::string &index_vector, - const int &position, const int &wp) { - return df.Define( - outputname, - [position, wp](const ROOT::RVec &index_vector, - const ROOT::RVec &IDs) { - Logger::get("physicsobject::tau::quantity::IDFlag_v9") - ->debug( - "position tau in pair {}, tau pair {}, id wp bit {}, vsjet ids {}", - position, index_vector, wp, IDs); - const int index = index_vector.at(position); - const int id_value = IDs.at(index, default_int); - if (id_value != default_int) - return std::min(1, int(id_value & 1 << (wp - 1))); - else - return int(id_value); - }, - {index_vector, ID}); + const std::string &ID, + const std::string &index_vector, const int &position, + const int &wp) { + return df.Define(outputname, + [position, wp](const ROOT::RVec &index_vector, + const ROOT::RVec &IDs) { + Logger::get("physicsobject::tau::quantity::IDFlag_v9") + ->debug("position tau in pair {}, tau pair {}, id " + "wp bit {}, vsjet ids {}", + position, index_vector, wp, IDs); + const int index = index_vector.at(position); + const int id_value = IDs.at(index, default_int); + if (id_value != default_int) + return std::min(1, int(id_value & 1 << (wp - 1))); + else + return int(id_value); + }, + {index_vector, ID}); } /** - * @brief This function writes out a flag that is true if a tau passes a specific - * tau ID working point (`wp`). The content of the tau ID branch changed in - * `nanoAODv12`. The working points are defied in integer steps (still saved as - * `UChar_t`). - * - * For `vsJet` and `vsEle`: 1 = VVVLoose, 2 = VVLoose, 3 = VLoose, 4 = Loose, + * @brief This function writes out a flag that is true if a tau passes a + * specific tau ID working point (`wp`). The content of the tau ID branch + * changed in `nanoAODv12`. The working points are defied in integer steps + * (still saved as `UChar_t`). + * + * For `vsJet` and `vsEle`: 1 = VVVLoose, 2 = VVLoose, 3 = VLoose, 4 = Loose, * 5 = Medium, 6 = Tight, 7 = VTight, 8 = VVTight * * For `vsMu`: 1 = VLoose, 2 = Loose, 3 = Medium, 4 = Tight - * + * * @param df input dataframe * @param outputname name of the output column containing the flag - * @param ID name of the column containing the tau ID values - * @param index_vector name of the column containing the vector with the relevant - * tau pair indices + * @param ID name of the column containing the tau ID values + * @param index_vector name of the column containing the vector with the + * relevant tau pair indices * @param position position in the index vector of the relevant tau in the pair * @param wp bit value of the WP that has to be passed * * @return a new dataframe containing the new column */ ROOT::RDF::RNode IDFlag_v12(ROOT::RDF::RNode df, const std::string &outputname, - const std::string &ID, const std::string &index_vector, - const int &position, const int &wp) { - return df.Define( - outputname, - [position, wp](const ROOT::RVec &index_vector, - const ROOT::RVec &IDs) { - Logger::get("physicsobject::tau::quantity::IDFlag_v12") - ->debug( - "position tau in pair {}, tau pair {}, id wp bit {}, vsjet ids {}", - position, index_vector, wp, IDs); - const int index = index_vector.at(position); - const int id_value = static_cast(IDs.at(index, default_int)); - if (id_value != default_int) - return int(id_value >= wp); - else - return id_value; - }, - {index_vector, ID}); + const std::string &ID, + const std::string &index_vector, + const int &position, const int &wp) { + return df.Define(outputname, + [position, wp](const ROOT::RVec &index_vector, + const ROOT::RVec &IDs) { + Logger::get("physicsobject::tau::quantity::IDFlag_v12") + ->debug("position tau in pair {}, tau pair {}, id " + "wp bit {}, vsjet ids {}", + position, index_vector, wp, IDs); + const int index = index_vector.at(position); + const int id_value = + static_cast(IDs.at(index, default_int)); + if (id_value != default_int) + return int(id_value >= wp); + else + return id_value; + }, + {index_vector, ID}); } } // end namespace quantity namespace scalefactor { /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against jets (`vsJet`). The scale factors are loaded from a correctionlib file - * using a specified scale factor name and variation. The variation and the scale - * factor itself is binned in transverse momenta (\f$p_T\f$) of hadronic taus - * for this function. - * - * Description of the bit map used to define the tau ID against jets working points of the - * DeepTau v2.1 tagger. - * vsJets | Value | Bit (value used in the config) + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against jets (`vsJet`). The scale factors are loaded from a + * correctionlib file using a specified scale factor name and variation. The + * variation and the scale factor itself is binned in transverse momenta + * (\f$p_T\f$) of hadronic taus for this function. + * + * Description of the bit map used to define the tau ID against jets working + * points of the DeepTau v2.1 tagger. vsJets | + * Value | Bit (value used in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VVVLoose | 1 | 1 @@ -1160,29 +1151,33 @@ namespace scalefactor { * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsJets ID scale factor + * @param outputname name of the output column containing the vsJets ID scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsJet ID correction * @param selected_dms list of allowed decay modes for which a scale factor * should be calculated * @param wp working point of the vsJet ID * @param vsele_wp working point of the vsEle ID - * @param sf_dependence variable dependence of the scale factor, options are "pt" or "dm" - * @param variation_pt30to35 name of the scale factor variation for \f$30 \leq p_T <35\f$ GeV, - * "nom" for nominal and "up"/"down" the up/down variation - * @param variation_pt35to40 name of the scale factor variation for \f$35 \leq p_T <40\f$ GeV, - * "nom" for nominal and "up"/"down" the up/down variation - * @param variation_pt40to500 name of the scale factor variation for \f$40 \leq p_T <500\f$ GeV, - * "nom" for nominal and "up"/"down" the up/down variation - * @param variation_pt500to1000 name of the scale factor variation for \f$500 \leq p_T <1000\f$ GeV, - * "nom" for nominal and "up"/"down" the up/down variation - * @param variation_pt1000toInf name of the scale factor variation for \f$1000 \leq p_T < \infty \f$ GeV, - * "nom" for nominal and "up"/"down" the up/down variation + * @param sf_dependence variable dependence of the scale factor, options are + * "pt" or "dm" + * @param variation_pt30to35 name of the scale factor variation for \f$30 \leq + * p_T <35\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt35to40 name of the scale factor variation for \f$35 \leq + * p_T <40\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt40to500 name of the scale factor variation for \f$40 \leq + * p_T <500\f$ GeV, "nom" for nominal and "up"/"down" the up/down variation + * @param variation_pt500to1000 name of the scale factor variation for \f$500 + * \leq p_T <1000\f$ GeV, "nom" for nominal and "up"/"down" the up/down + * variation + * @param variation_pt1000toInf name of the scale factor variation for \f$1000 + * \leq p_T < \infty \f$ GeV, "nom" for nominal and "up"/"down" the up/down + * variation * * @return a new dataframe containing the new column * @@ -1192,37 +1187,33 @@ namespace scalefactor { ROOT::RDF::RNode Id_vsJet_lt(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::vector &selected_dms, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::vector &selected_dms, const std::string &wp, + const std::string &vsele_wp, const std::string &sf_dependence, const std::string &variation_pt30to35, const std::string &variation_pt35to40, const std::string &variation_pt40to500, const std::string &variation_pt500to1000, const std::string &variation_pt1000toInf) { - + const std::map variations = { - {30.0f, variation_pt30to35}, - {35.0f, variation_pt35to40}, - {40.0f, variation_pt40to500}, - {500.0f, variation_pt500to1000}, - {1000.0f, variation_pt1000toInf}, - {100000.0f, variation_pt1000toInf}, + {30.0f, variation_pt30to35}, {35.0f, variation_pt35to40}, + {40.0f, variation_pt40to500}, {500.0f, variation_pt500to1000}, + {1000.0f, variation_pt1000toInf}, {100000.0f, variation_pt1000toInf}, }; Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt") ->debug("Setting up function for tau id vsJet sf"); - Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt")->debug("ID - Name {}", sf_name); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt") + ->debug("ID - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto sf_calculator = [evaluator, wp, vsele_wp, variations, - sf_dependence, selected_dms, - sf_name](const float &pt, const int &decay_mode, - const int &gen_match) { - Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt")->debug("ID - decayMode {}", decay_mode); + auto sf_calculator = [evaluator, wp, vsele_wp, variations, sf_dependence, + selected_dms, + sf_name](const float &pt, const int &decay_mode, + const int &gen_match) { + Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt") + ->debug("ID - decayMode {}", decay_mode); // only calculate SFs for allowed tau decay modes (also excludes default // values due to tau energy correction shifts below good tau pt // selection) @@ -1230,35 +1221,40 @@ Id_vsJet_lt(ROOT::RDF::RNode df, if (std::find(selected_dms.begin(), selected_dms.end(), decay_mode) != selected_dms.end()) { auto it = variations.upper_bound(pt); - if (it != variations.begin()){ + if (it != variations.begin()) { it = std::prev(it); std::string variation = it->second; Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt") - ->debug("ID {} - pt {}, decay_mode {}, gen_match {}, wp {}, " + ->debug( + "ID {} - pt {}, decay_mode {}, gen_match {}, wp {}, " "vsele_wp {}, variation {}, sf_dependence {}", sf_name, pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence); - sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence}); + sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, + vsele_wp, variation, sf_dependence}); } else { sf = 1.; } } - Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet_lt") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); + auto df1 = + df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); return df1; } /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against jets (`vsJet`). The scale factors are loaded from a correctionlib file - * using a specified scale factor name and variation. The variation and the scale - * factor itself is binned in decay modes of hadronic taus for this function. - * - * Description of the bit map used to define the tau ID against jets working points of the - * DeepTau v2.1 or v2.5 tagger. - * vsJets | Value | Bit (value used in the config) + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against jets (`vsJet`). The scale factors are loaded from a + * correctionlib file using a specified scale factor name and variation. The + * variation and the scale factor itself is binned in decay modes of hadronic + * taus for this function. + * + * Description of the bit map used to define the tau ID against jets working + * points of the DeepTau v2.1 or v2.5 tagger. vsJets | Value | Bit (value used + * in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VVVLoose | 1 | 1 @@ -1273,59 +1269,60 @@ Id_vsJet_lt(ROOT::RDF::RNode df, * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsJets ID scale factor + * @param outputname name of the output column containing the vsJets ID scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsJet ID correction * @param wp working point of the vsJet ID * @param vsele_wp working point of the vsEle ID - * @param sf_dependence variable dependence of the scale factor, options are "pt" - * (which is dm+pt) or "dm" (which is dm only) - * @param variation_dm0 name of the scale factor variation for decay mode 0, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_dm1 name of the scale factor variation for decay mode 1, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_dm10 name of the scale factor variation for decay mode 10, "nom" for nominal - * and "up"/"down" the up/down variation - * @param variation_dm11 name of the scale factor variation for decay mode 11, "nom" for nominal - * and "up"/"down" the up/down variation + * @param sf_dependence variable dependence of the scale factor, options are + * "pt" (which is dm+pt) or "dm" (which is dm only) + * @param variation_dm0 name of the scale factor variation for decay mode 0, + * "nom" for nominal and "up"/"down" the up/down variation + * @param variation_dm1 name of the scale factor variation for decay mode 1, + * "nom" for nominal and "up"/"down" the up/down variation + * @param variation_dm10 name of the scale factor variation for decay mode 10, + * "nom" for nominal and "up"/"down" the up/down variation + * @param variation_dm11 name of the scale factor variation for decay mode 11, + * "nom" for nominal and "up"/"down" the up/down variation * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Id_vsJet( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, const std::string &sf_name, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, - const std::string &variation_dm0, - const std::string &variation_dm1, - const std::string &variation_dm10, - const std::string &variation_dm11) { - +ROOT::RDF::RNode +Id_vsJet(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::string &wp, const std::string &vsele_wp, + const std::string &sf_dependence, const std::string &variation_dm0, + const std::string &variation_dm1, const std::string &variation_dm10, + const std::string &variation_dm11) { + const std::unordered_map variations = { - {0, variation_dm0}, - {1, variation_dm1}, + {0, variation_dm0}, + {1, variation_dm1}, {10, variation_dm10}, {11, variation_dm11}, }; Logger::get("physicsobject::tau::scalefactor::Id_vsJet") ->debug("Setting up function for tau ID vsJet SF (DM binned only)"); - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("SF - Name {}", sf_name); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("SF - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto sf_calculator = [evaluator, wp, vsele_wp, variations, - sf_dependence, sf_name](const float &pt, const int &decay_mode, - const int &gen_match) { - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("SF - decayMode {}", decay_mode); + auto sf_calculator = [evaluator, wp, vsele_wp, variations, sf_dependence, + sf_name](const float &pt, const int &decay_mode, + const int &gen_match) { + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("SF - decayMode {}", decay_mode); // only calculate SFs for allowed tau decay modes (also excludes default - // values due to tau energy correction shifts below good tau pt selection) + // values due to tau energy correction shifts below good tau pt + // selection) double sf = 1.; if (auto it = variations.find(decay_mode); it != variations.end()) { std::string variation = it->second; @@ -1334,27 +1331,28 @@ ROOT::RDF::RNode Id_vsJet( "vsele_wp {}, variation {}, sf_dependence {}", sf_name, pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence); - sf = evaluator->evaluate( - {pt, decay_mode, gen_match, wp, vsele_wp, - variation, sf_dependence}); + sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, vsele_wp, + variation, sf_dependence}); } - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); + auto df1 = + df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); return df1; } /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against jets (`vsJet`). The scale factors are loaded from a correctionlib file - * using a specified scale factor name and variation. The variation and the scale - * factor itself is binned in decay modes and transverse momentum of hadronic taus - * for this function. - * - * Description of the bit map used to define the tau ID against jets working points of the - * DeepTau v2.1 and v2.5 tagger. - * vsJets | Value | Bit (value used in the config) + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against jets (`vsJet`). The scale factors are loaded from a + * correctionlib file using a specified scale factor name and variation. The + * variation and the scale factor itself is binned in decay modes and transverse + * momentum of hadronic taus for this function. + * + * Description of the bit map used to define the tau ID against jets working + * points of the DeepTau v2.1 and v2.5 tagger. vsJets | Value | Bit (value used + * in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VVVLoose | 1 | 1 @@ -1369,18 +1367,19 @@ ROOT::RDF::RNode Id_vsJet( * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsJets ID scale factor + * @param outputname name of the output column containing the vsJets ID scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsJet ID correction * @param wp working point of the vsJet ID * @param vsele_wp working point of the vsEle ID - * @param sf_dependence variable dependence of the scale factor, options are "pt" - * (which is dm+pt) or "dm" (which is dm only) + * @param sf_dependence variable dependence of the scale factor, options are + * "pt" (which is dm+pt) or "dm" (which is dm only) * @param variation_dm0_pt20to40 variation for decay mode 0 and * \f$20 \leq p_T <40\f$ GeV, options are "nom", "up", "down" * @param variation_dm0_pt40toInf variation for decay mode 0 and @@ -1391,7 +1390,7 @@ ROOT::RDF::RNode Id_vsJet( * 40 GeV \f$\leq p_{T,\tau}\f$, options are "nom", "up", "down" * @param variation_dm10_pt20to40 variation for decay mode 10 and * \f$20 \leq p_T <40\f$ GeV, options are "nom", "up", "down" - * @param variation_dm10_pt40toInf variation for decay mode 10 and + * @param variation_dm10_pt40toInf variation for decay mode 10 and * 40 GeV \f$\leq p_{T,\tau}\f$, options are "nom", "up", "down" * @param variation_dm11_pt20to40 variation for decay mode 11 and * \f$20 \leq p_T <40\f$ GeV, options are "nom", "up", "down" @@ -1400,75 +1399,90 @@ ROOT::RDF::RNode Id_vsJet( * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode Id_vsJet( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &gen_match, - const std::string &sf_file, const std::string &sf_name, - const std::string &wp, const std::string &vsele_wp, - const std::string &sf_dependence, - const std::string &variation_dm0_pt20to40, const std::string &variation_dm0_pt40toInf, - const std::string &variation_dm1_pt20to40, const std::string &variation_dm1_pt40toInf, - const std::string &variation_dm10_pt20to40, const std::string &variation_dm10_pt40toInf, - const std::string &variation_dm11_pt20to40, const std::string &variation_dm11_pt40toInf) { - +ROOT::RDF::RNode +Id_vsJet(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &gen_match, + const std::string &sf_file, const std::string &sf_name, + const std::string &wp, const std::string &vsele_wp, + const std::string &sf_dependence, + const std::string &variation_dm0_pt20to40, + const std::string &variation_dm0_pt40toInf, + const std::string &variation_dm1_pt20to40, + const std::string &variation_dm1_pt40toInf, + const std::string &variation_dm10_pt20to40, + const std::string &variation_dm10_pt40toInf, + const std::string &variation_dm11_pt20to40, + const std::string &variation_dm11_pt40toInf) { + const std::unordered_map> variations = { - {0, {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, - {1, {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, - {10, {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, - {11, {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, + {0, + {{20.0f, variation_dm0_pt20to40}, {40.0f, variation_dm0_pt40toInf}}}, + {1, + {{20.0f, variation_dm1_pt20to40}, {40.0f, variation_dm1_pt40toInf}}}, + {10, + {{20.0f, variation_dm10_pt20to40}, {40.0f, variation_dm10_pt40toInf}}}, + {11, + {{20.0f, variation_dm11_pt20to40}, {40.0f, variation_dm11_pt40toInf}}}, }; Logger::get("physicsobject::tau::scalefactor::Id_vsJet") ->debug("Setting up function for tau ID vsJet SF (DM & pT binned)"); - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("SF - Name {}", sf_name); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("SF - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto sf_calculator = [evaluator, wp, vsele_wp, variations, - sf_dependence, sf_name](const float &pt, const int &decay_mode, - const int &gen_match) { - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("SF - decayMode {}", decay_mode); + auto sf_calculator = [evaluator, wp, vsele_wp, variations, sf_dependence, + sf_name](const float &pt, const int &decay_mode, + const int &gen_match) { + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("SF - decayMode {}", decay_mode); // only calculate SFs for allowed tau decay modes (also excludes default - // values due to tau energy correction shifts below good tau pt selection) + // values due to tau energy correction shifts below good tau pt + // selection) double sf = 1.; - if (auto dm_it = variations.find(decay_mode); dm_it != variations.end()) { + if (auto dm_it = variations.find(decay_mode); + dm_it != variations.end()) { const auto &pt_map = dm_it->second; - + auto pt_it = pt_map.upper_bound(pt); - - if (pt_it != pt_map.begin()){ + + if (pt_it != pt_map.begin()) { pt_it = std::prev(pt_it); // Move back to the lower bound key std::string variation = pt_it->second; - + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") - ->debug("SF {} - pt {}, decay_mode {}, gen_match {}, wp {}, " + ->debug( + "SF {} - pt {}, decay_mode {}, gen_match {}, wp {}, " "vsele_wp {}, variation {}, sf_dependence {}", sf_name, pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence); - - sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, vsele_wp, variation, sf_dependence}); + + sf = evaluator->evaluate({pt, decay_mode, gen_match, wp, + vsele_wp, variation, sf_dependence}); } } - Logger::get("physicsobject::tau::scalefactor::Id_vsJet")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Id_vsJet") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); + auto df1 = + df.Define(outputname, sf_calculator, {pt, decay_mode, gen_match}); return df1; } - /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against electrons (`vsEle`). The scale factors are loaded from a correctionlib file - * using a specified scale factor name and variation. The variation and the scale - * factor itself is binned in pseudorapidities of hadronic taus for this function. - * - * Description of the bit map used to define the tau ID against electrons working points of the - * DeepTau v2.1 tagger. - * vsElectrons | Value | Bit (value used in the config) + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against electrons (`vsEle`). The scale factors are loaded from a + * correctionlib file using a specified scale factor name and variation. The + * variation and the scale factor itself is binned in pseudorapidities of + * hadronic taus for this function. + * + * Description of the bit map used to define the tau ID against electrons + * working points of the DeepTau v2.1 tagger. vsElectrons | Value | Bit (value + * used in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VVVLoose | 1 | 1 @@ -1483,35 +1497,37 @@ ROOT::RDF::RNode Id_vsJet( * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsEle ID scale factor + * @param outputname name of the output column containing the vsEle ID scale + * factor * @param eta name of the column containing the pseudorapidity of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) - * @param era data-taking era, e.g. "2017" or "2018", needed to set the eta boundaries - * for the endcap region + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * @param era data-taking era, e.g. "2017" or "2018", needed to set the eta + * boundaries for the endcap region * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsEle ID correction * @param wp working point of the vsEle ID - * @param variation_barrel name of the scale factor variation for the barrel region + * @param variation_barrel name of the scale factor variation for the barrel + * region * (\f$|\eta| <1.46\f$), "nom" for nominal and "up"/"down" the up/down variation - * @param variation_endcap name of the scale factor variation for the endcap region - * (\f$1.558 \leq |\eta| <2.3\f$), "nom" for nominal and "up"/"down" the up/down variation + * @param variation_endcap name of the scale factor variation for the endcap + * region + * (\f$1.558 \leq |\eta| <2.3\f$), "nom" for nominal and "up"/"down" the up/down + * variation * * @return a new dataframe containing the new column - * - * @note This function is intended to be used with Run 2 analyses. The scale factor additionally - * depends on the decay mode of the tau in Run 3. For Run 3 analyses, use the overloaded version - * of this function. + * + * @note This function is intended to be used with Run 2 analyses. The scale + * factor additionally depends on the decay mode of the tau in Run 3. For Run 3 + * analyses, use the overloaded version of this function. */ ROOT::RDF::RNode Id_vsEle(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &eta, - const std::string &decay_mode, - const std::string &gen_match, + const std::string &outputname, const std::string &eta, + const std::string &decay_mode, const std::string &gen_match, const std::string &sf_file, const std::string &sf_name, const std::string &wp, const std::string &era, const std::string &variation_barrel, @@ -1519,70 +1535,78 @@ Id_vsEle(ROOT::RDF::RNode df, Logger::get("physicsobject::tau::scalefactor::Id_vsEle") ->debug("Setting up function for tau id vsEle sf"); - Logger::get("physicsobject::tau::scalefactor::Id_vsEle")->debug("ID - Name {}", sf_name); + Logger::get("physicsobject::tau::scalefactor::Id_vsEle") + ->debug("ID - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - auto sf_calculator = [evaluator, era, wp, variation_barrel, variation_endcap, - sf_name](const float &eta, const int &dm, const int &gen_match) { - double sf = 1.; - - // set edges of barrel and endcap region - - double max_abs_eta_barrel = 1.46; - double min_abs_eta_endcap = 1.558; - double max_abs_eta_endcap = 2.3; - if (std::stoi(era.substr(0, 4)) >= 2022) max_abs_eta_endcap = 2.5; - - // exclude default values due to tau energy correction shifts below good tau - // pt selection - if (eta > -5.0) { - Logger::get("physicsobject::tau::scalefactor::Id_vsEle") - ->debug("ID {} - eta {}, dm {}, gen_match {}, wp {}, variation_barrel " - "{}, variation_endcap {}", - sf_name, eta, dm, gen_match, wp, variation_barrel, - variation_endcap); - // the eta cuts are taken from the correctionlib json file to define - // barrel and endcap - if (sf_name == "DeepTau2017v2p1VSe") { - // SFs for DeepTau2017v2p1 depend on eta - if (std::abs(eta) < max_abs_eta_barrel) { - sf = evaluator->evaluate( - {eta, gen_match, wp, variation_barrel}); - } else if (std::abs(eta) >= min_abs_eta_endcap && std::abs(eta) < max_abs_eta_endcap) { - sf = evaluator->evaluate( - {eta, gen_match, wp, variation_endcap}); - } else { - sf = 1.; - } - } else { - // SFs for DeepTau2018v2p5 depend on eta and the decay mode - if (std::abs(eta) < max_abs_eta_barrel) { - sf = evaluator->evaluate( - {eta, dm, gen_match, wp, variation_barrel}); - } else if (std::abs(eta) >= min_abs_eta_endcap && std::abs(eta) < max_abs_eta_endcap) { - sf = evaluator->evaluate( - {eta, dm, gen_match, wp, variation_endcap}); + auto sf_calculator = + [evaluator, era, wp, variation_barrel, variation_endcap, + sf_name](const float &eta, const int &dm, const int &gen_match) { + double sf = 1.; + + // set edges of barrel and endcap region + + double max_abs_eta_barrel = 1.46; + double min_abs_eta_endcap = 1.558; + double max_abs_eta_endcap = 2.3; + if (std::stoi(era.substr(0, 4)) >= 2022) + max_abs_eta_endcap = 2.5; + + // exclude default values due to tau energy correction shifts below + // good tau pt selection + if (eta > -5.0) { + Logger::get("physicsobject::tau::scalefactor::Id_vsEle") + ->debug("ID {} - eta {}, dm {}, gen_match {}, wp {}, " + "variation_barrel " + "{}, variation_endcap {}", + sf_name, eta, dm, gen_match, wp, variation_barrel, + variation_endcap); + // the eta cuts are taken from the correctionlib json file to + // define barrel and endcap + if (sf_name == "DeepTau2017v2p1VSe") { + // SFs for DeepTau2017v2p1 depend on eta + if (std::abs(eta) < max_abs_eta_barrel) { + sf = evaluator->evaluate( + {eta, gen_match, wp, variation_barrel}); + } else if (std::abs(eta) >= min_abs_eta_endcap && + std::abs(eta) < max_abs_eta_endcap) { + sf = evaluator->evaluate( + {eta, gen_match, wp, variation_endcap}); + } else { + sf = 1.; + } } else { - sf = 1.; + // SFs for DeepTau2018v2p5 depend on eta and the decay mode + if (std::abs(eta) < max_abs_eta_barrel) { + sf = evaluator->evaluate( + {eta, dm, gen_match, wp, variation_barrel}); + } else if (std::abs(eta) >= min_abs_eta_endcap && + std::abs(eta) < max_abs_eta_endcap) { + sf = evaluator->evaluate( + {eta, dm, gen_match, wp, variation_endcap}); + } else { + sf = 1.; + } } } - } - Logger::get("physicsobject::tau::scalefactor::Id_vsEle")->debug("Scale Factor {}", sf); - return sf; - }; + Logger::get("physicsobject::tau::scalefactor::Id_vsEle") + ->debug("Scale Factor {}", sf); + return sf; + }; auto df1 = df.Define(outputname, sf_calculator, {eta, decay_mode, gen_match}); return df1; } /** - * @brief This function calculates scale factors (SFs) for tau identification (ID) - * against muons (`vsMu`). The scale factors are loaded from a correctionlib file - * using a specified scale factor name and variation. The variation and the scale - * factor itself is binned in pseudorapidities of hadronic taus for this function. - * - * Description of the bit map used to define the tau ID against muons working points of the - * DeepTau v2.1 tagger. - * vsMuons | Value | Bit (value used in the config) + * @brief This function calculates scale factors (SFs) for tau identification + * (ID) against muons (`vsMu`). The scale factors are loaded from a + * correctionlib file using a specified scale factor name and variation. The + * variation and the scale factor itself is binned in pseudorapidities of + * hadronic taus for this function. + * + * Description of the bit map used to define the tau ID against muons working + * points of the DeepTau v2.1 tagger. vsMuons | + * Value | Bit (value used in the config) * ------------------------------------|-------|------- * no ID selection (takes every tau) | 0 | - * VLoose | 1 | 1 @@ -1593,79 +1617,85 @@ Id_vsEle(ROOT::RDF::RNode df, * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the vsMu ID scale factor + * @param outputname name of the output column containing the vsMu ID scale + * factor * @param eta name of the column containing the pseudorapidity of a tau * @param gen_match name of the column with the matching information of the - * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt mu, - * 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) + * hadronic tau to generator-level particles (matches are: 1=prompt e, 2=prompt + * mu, 3=tau->e, 4=tau->mu, 5=had. tau, 0=unmatched) * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the vsMu ID correction * @param wp working point of the vsMu ID * @param wp_ele working point of the vsEle ID * @param wp_jet working point of the vsJet ID - * @param era string defining the currently processed era, needed due to different - * kind of scale factor dependencies introduced by TAU POG for different eras + * @param era string defining the currently processed era, needed due to + * different kind of scale factor dependencies introduced by TAU POG for + * different eras * @param variation_wheel1 name of the scale factor variation for the muon wheel * (\f$|\eta| <0.4\f$), "nom" for nominal and "up"/"down" the up/down variation * @param variation_wheel2 name of the scale factor variation for the muon wheel - * (\f$0.4 \leq |\eta| <0.8\f$), "nom" for nominal and "up"/"down" the up/down variation + * (\f$0.4 \leq |\eta| <0.8\f$), "nom" for nominal and "up"/"down" the up/down + * variation * @param variation_wheel3 name of the scale factor variation for the muon wheel - * (\f$0.8 \leq |\eta| <1.2\f$), "nom" for nominal and "up"/"down" the up/down variation + * (\f$0.8 \leq |\eta| <1.2\f$), "nom" for nominal and "up"/"down" the up/down + * variation * @param variation_wheel4 name of the scale factor variation for the muon wheel - * (\f$1.2 \leq |\eta| <1.7\f$), "nom" for nominal and "up"/"down" the up/down variation + * (\f$1.2 \leq |\eta| <1.7\f$), "nom" for nominal and "up"/"down" the up/down + * variation * @param variation_wheel5 name of the scale factor variation for the muon wheel - * (\f$1.7 \leq |\eta| <2.3\f$), "nom" for nominal and "up"/"down" the up/down variation + * (\f$1.7 \leq |\eta| <2.3\f$), "nom" for nominal and "up"/"down" the up/down + * variation * * @return a new dataframe containing the new column */ -ROOT::RDF::RNode -Id_vsMu(ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &eta, - const std::string &gen_match, - const std::string &sf_file, - const std::string &sf_name, - const std::string &wp, - const std::string &wp_ele, - const std::string &wp_jet, - const std::string &era, - const std::string &variation_wheel1, - const std::string &variation_wheel2, - const std::string &variation_wheel3, - const std::string &variation_wheel4, - const std::string &variation_wheel5) { - +ROOT::RDF::RNode Id_vsMu( + ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &eta, + const std::string &gen_match, const std::string &sf_file, + const std::string &sf_name, const std::string &wp, + const std::string &wp_ele, const std::string &wp_jet, + const std::string &era, const std::string &variation_wheel1, + const std::string &variation_wheel2, const std::string &variation_wheel3, + const std::string &variation_wheel4, const std::string &variation_wheel5) { + const std::map variations = { {0.0f, variation_wheel1}, {0.4f, variation_wheel2}, {0.8f, variation_wheel3}, {1.2f, variation_wheel4}, {1.7f, variation_wheel5}, - {2.4f, variation_wheel5}, // 2.4 to cover full muon system acceptance for Run 3 taus - // should not affect Run 2 analyses, which cut on |eta| < 2.3 + {2.4f, variation_wheel5}, // 2.4 to cover full muon system acceptance + // for Run 3 taus should not affect Run 2 + // analyses, which cut on |eta| < 2.3 }; - Logger::get("physicsobject::tau::scalefactor::Id_vsMu")->debug("Setting up function for tau id vsMu sf"); - Logger::get("physicsobject::tau::scalefactor::Id_vsMu")->debug("ID - Name {}", sf_name); + Logger::get("physicsobject::tau::scalefactor::Id_vsMu") + ->debug("Setting up function for tau id vsMu sf"); + Logger::get("physicsobject::tau::scalefactor::Id_vsMu") + ->debug("ID - Name {}", sf_name); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); auto sf_calculator = [evaluator, wp, wp_ele, wp_jet, era, variations, - sf_name](const float &eta, const int &gen_match) { + sf_name](const float &eta, const int &gen_match) { double sf = 1.; - // exclude default values due to tau energy correction shifts below good tau - // pt selection + // exclude default values due to tau energy correction shifts below good + // tau pt selection if (eta > -5.0) { auto it = variations.upper_bound(abs(eta)); - if (it != variations.begin()){ + if (it != variations.begin()) { it = std::prev(it); std::string variation = it->second; if (era == "2024" || era == "2025") { Logger::get("physicsobject::tau::scalefactor::Id_vsMu") - ->debug("ID {} - eta {}, gen_match {}, wp {}, wp ele {}, wp jet {}, variation {}", - sf_name, eta, gen_match, wp, wp_ele, wp_jet, variation); - sf = evaluator->evaluate({eta, gen_match, wp, wp_ele, wp_jet, variation}); + ->debug("ID {} - eta {}, gen_match {}, wp {}, wp ele " + "{}, wp jet {}, variation {}", + sf_name, eta, gen_match, wp, wp_ele, wp_jet, + variation); + sf = evaluator->evaluate( + {eta, gen_match, wp, wp_ele, wp_jet, variation}); } else { Logger::get("physicsobject::tau::scalefactor::Id_vsMu") - ->debug("ID {} - eta {}, gen_match {}, wp {}, variation {}", + ->debug( + "ID {} - eta {}, gen_match {}, wp {}, variation {}", sf_name, eta, gen_match, wp, variation); sf = evaluator->evaluate({eta, gen_match, wp, variation}); } @@ -1673,48 +1703,49 @@ Id_vsMu(ROOT::RDF::RNode df, sf = 1.; } } - Logger::get("physicsobject::tau::scalefactor::Id_vsMu")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Id_vsMu") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = - df.Define(outputname, sf_calculator, {eta, gen_match}); + auto df1 = df.Define(outputname, sf_calculator, {eta, gen_match}); return df1; } /** - * @brief This function calculates scale factors (SFs) for tau triggers. The scale factors - * are loaded from a correctionlib file using a specified scale factor name and variation. - * The scale factor is binned in \f$p_T\f$ and decay modes of hadronic taus for this function. + * @brief This function calculates scale factors (SFs) for tau triggers. The + * scale factors are loaded from a correctionlib file using a specified scale + * factor name and variation. The scale factor is binned in \f$p_T\f$ and decay + * modes of hadronic taus for this function. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the trigger scale factor + * @param outputname name of the output column containing the trigger scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param sf_file path to the file with the tau scale factors * @param sf_name name of the tau scale factor for the trigger correction * @param trigger_name name of the trigger, e.g. "ditau", "etau", "mutau" * @param wp working point of the vsJet ID - * @param corr_type type of the value to be read out, options are "sf" (for + * @param corr_type type of the value to be read out, options are "sf" (for * scale factors), "eff_data", "eff_mc" * @param variation name the scale factor variation, "nom" for the nominal * scale factor and "up"/"down" for the up/down variation * * @return a new dataframe containing the new column * - * @warning This function is deprecated. Use the overloaded function with the additional - * parameter `trigger_flag` instead. + * @warning This function is deprecated. Use the overloaded function with the + * additional parameter `trigger_flag` instead. */ ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &sf_file, - const std::string &sf_name, - const std::string &trigger_name, const std::string &wp, - const std::string &corr_type, const std::string &variation) { + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &sf_file, + const std::string &sf_name, const std::string &trigger_name, + const std::string &wp, const std::string &corr_type, + const std::string &variation) { Logger::get("physicsobject::tau::scalefactor::Trigger") ->warn("Function is deprecated, use the overloaded version instead"); Logger::get("physicsobject::tau::scalefactor::Trigger") @@ -1722,29 +1753,32 @@ Trigger(ROOT::RDF::RNode df, Logger::get("physicsobject::tau::scalefactor::Trigger") ->debug("ID - Name {}, file {}", sf_name, sf_file); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - Logger::get("physicsobject::tau::scalefactor::Trigger")->debug("WP {} - type {}", wp, corr_type); - auto sf_calculator = [evaluator, trigger_name, wp, corr_type, variation, sf_name]( - const float &pt, const int &decay_mode) { + Logger::get("physicsobject::tau::scalefactor::Trigger") + ->debug("WP {} - type {}", wp, corr_type); + auto sf_calculator = [evaluator, trigger_name, wp, corr_type, variation, + sf_name](const float &pt, const int &decay_mode) { float sf = 1.; try { Logger::get("physicsobject::tau::scalefactor::Trigger") ->debug("ID {} - decaymode {}, wp {} " - "pt {}, type {}, variation {}", - sf_name, decay_mode, wp, pt, corr_type, variation); + "pt {}, type {}, variation {}", + sf_name, decay_mode, wp, pt, corr_type, variation); if (pt >= 0.) { if (decay_mode == 0 || decay_mode == 1 || decay_mode == 10 || decay_mode == 11) { - sf = evaluator->evaluate( - {pt, decay_mode, trigger_name, wp, corr_type, variation}); + sf = evaluator->evaluate({pt, decay_mode, trigger_name, wp, + corr_type, variation}); } else { - sf = evaluator->evaluate({pt, -1, trigger_name, wp, corr_type, variation}); + sf = evaluator->evaluate( + {pt, -1, trigger_name, wp, corr_type, variation}); } } } catch (const std::runtime_error &e) { Logger::get("physicsobject::tau::scalefactor::Trigger") ->debug("SF evaluation for {} failed for pt {}", sf_name, pt); } - Logger::get("physicsobject::tau::scalefactor::Trigger")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Trigger") + ->debug("Scale Factor {}", sf); return sf; }; auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode}); @@ -1752,17 +1786,18 @@ Trigger(ROOT::RDF::RNode df, } /** - * @brief This function calculates scale factors (SFs) for tau triggers. The scale factors - * are loaded from a correctionlib file using a specified scale factor name and variation. - * The scale factor is binned in \f$p_T\f$ and decay modes of hadronic taus for this function. - * This function only uses the scale factor from the correctionlib evaluation if the - * corresponding trigger flag is set to `true`. Otherwise, it returns a scale factor of - * 1.0. + * @brief This function calculates scale factors (SFs) for tau triggers. The + * scale factors are loaded from a correctionlib file using a specified scale + * factor name and variation. The scale factor is binned in \f$p_T\f$ and decay + * modes of hadronic taus for this function. This function only uses the scale + * factor from the correctionlib evaluation if the corresponding trigger flag is + * set to `true`. Otherwise, it returns a scale factor of 1.0. * * @param df input dataframe * @param correction_manager correction manager responsible for loading the * tau scale factor file - * @param outputname name of the output column containing the trigger scale factor + * @param outputname name of the output column containing the trigger scale + * factor * @param pt name of the column containing the transverse momentum of a tau * @param decay_mode name of the column containing the decay mode of the tau * @param trigger_flag name of the column containing the trigger flag @@ -1770,7 +1805,7 @@ Trigger(ROOT::RDF::RNode df, * @param sf_name name of the tau scale factor for the trigger correction * @param trigger_name name of the trigger, e.g. "ditau", "etau", "mutau" * @param wp working point of the vsJet ID - * @param corr_type type of the value to be read out, options are "sf" (for + * @param corr_type type of the value to be read out, options are "sf" (for * scale factors), "eff_data", "eff_mc" * @param variation name the scale factor variation, "nom" for the nominal * scale factor and "up"/"down" for the up/down variation @@ -1780,11 +1815,9 @@ Trigger(ROOT::RDF::RNode df, ROOT::RDF::RNode Trigger(ROOT::RDF::RNode df, correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, - const std::string &pt, const std::string &decay_mode, - const std::string &trigger_flag, - const std::string &sf_file, - const std::string &sf_name, + const std::string &outputname, const std::string &pt, + const std::string &decay_mode, const std::string &trigger_flag, + const std::string &sf_file, const std::string &sf_name, const std::string &trigger_name, const std::string &wp, const std::string &corr_type, const std::string &variation) { @@ -1793,33 +1826,38 @@ Trigger(ROOT::RDF::RNode df, Logger::get("physicsobject::tau::scalefactor::Trigger") ->debug("ID - Name {}, file {}", sf_name, sf_file); auto evaluator = correction_manager.loadCorrection(sf_file, sf_name); - Logger::get("physicsobject::tau::scalefactor::Trigger")->debug("WP {} - type {}", wp, corr_type); - auto sf_calculator = [evaluator, trigger_name, wp, corr_type, variation, sf_name]( - const float &pt, const int &decay_mode, - const bool &trigger_flag) { + Logger::get("physicsobject::tau::scalefactor::Trigger") + ->debug("WP {} - type {}", wp, corr_type); + auto sf_calculator = [evaluator, trigger_name, wp, corr_type, variation, + sf_name](const float &pt, const int &decay_mode, + const bool &trigger_flag) { float sf = 1.; try { Logger::get("physicsobject::tau::scalefactor::Trigger") - ->debug("ID {} - decaymode {}, wp {} " - "pt {}, trigger_flag {}, type {}, variation {}", - sf_name, decay_mode, wp, pt, trigger_flag, corr_type, variation); + ->debug("ID {} - decaymode {}, wp {} " + "pt {}, trigger_flag {}, type {}, variation {}", + sf_name, decay_mode, wp, pt, trigger_flag, corr_type, + variation); if (pt >= 0. && trigger_flag) { if (decay_mode == 0 || decay_mode == 1 || decay_mode == 10 || decay_mode == 11) { - sf = evaluator->evaluate( - {pt, decay_mode, trigger_name, wp, corr_type, variation}); + sf = evaluator->evaluate({pt, decay_mode, trigger_name, wp, + corr_type, variation}); } else { - sf = evaluator->evaluate({pt, -1, trigger_name, wp, corr_type, variation}); + sf = evaluator->evaluate( + {pt, -1, trigger_name, wp, corr_type, variation}); } } } catch (const std::runtime_error &e) { Logger::get("physicsobject::tau::scalefactor::Trigger") ->debug("SF evaluation for {} failed for pt {}", sf_name, pt); } - Logger::get("physicsobject::tau::scalefactor::Trigger")->debug("Scale Factor {}", sf); + Logger::get("physicsobject::tau::scalefactor::Trigger") + ->debug("Scale Factor {}", sf); return sf; }; - auto df1 = df.Define(outputname, sf_calculator, {pt, decay_mode, trigger_flag}); + auto df1 = + df.Define(outputname, sf_calculator, {pt, decay_mode, trigger_flag}); return df1; } } // end namespace scalefactor diff --git a/src/triggers.cxx b/src/triggers.cxx index 5c2e07dc..9f6d7169 100644 --- a/src/triggers.cxx +++ b/src/triggers.cxx @@ -22,12 +22,13 @@ namespace trigger { /** * @brief This function tries to match an object with a trigger object. An * object is successfully matched, if they overlap within a given \f$\Delta R\f$ - * cone and the \f$p_T\f$ / \f$|\eta|\f$ thresholds are met. Further, the trigger - * object ID and the trigger object filter bit are set to the correct value. + * cone and the \f$p_T\f$ / \f$|\eta|\f$ thresholds are met. Further, the + * trigger object ID and the trigger object filter bit are set to the correct + * value. * * For the trigger objects, two additional quantities are stored, the ID of the - * particle and some further information on the trigger path encoded in a bitmap. - * The trigger object ID is encoded as follows: + * particle and some further information on the trigger path encoded in a + * bitmap. The trigger object ID is encoded as follows: * @code * 1 = Jet * 2 = MET @@ -85,20 +86,19 @@ namespace trigger { * * @return boolean value indicating whether a match was found */ -bool matchParticle(const ROOT::Math::PtEtaPhiMVector &particle, - ROOT::RVec &triggerobject_pts, - ROOT::RVec &triggerobject_etas, - ROOT::RVec &triggerobject_phis, - ROOT::RVec &triggerobject_ids, - ROOT::RVec &triggerobject_filterbits, - const float &pt_threshold, const float &eta_threshold, - const int &trigger_particle_id_value, const int &trigger_bit_value, - const float &deltaR_threshold) { +bool matchParticle( + const ROOT::Math::PtEtaPhiMVector &particle, + ROOT::RVec &triggerobject_pts, ROOT::RVec &triggerobject_etas, + ROOT::RVec &triggerobject_phis, ROOT::RVec &triggerobject_ids, + ROOT::RVec &triggerobject_filterbits, const float &pt_threshold, + const float &eta_threshold, const int &trigger_particle_id_value, + const int &trigger_bit_value, const float &deltaR_threshold) { Logger::get("trigger::matchParticle")->debug("Checking Triggerobjects"); Logger::get("trigger::matchParticle") ->debug("Total number of triggerobjects: {}", triggerobject_pts.size()); for (std::size_t idx = 0; idx < triggerobject_pts.size(); ++idx) { - Logger::get("trigger::matchParticle")->debug("Triggerobject Nr. {}", idx); + Logger::get("trigger::matchParticle") + ->debug("Triggerobject Nr. {}", idx); auto triggerobject = ROOT::Math::RhoEtaPhiVectorF( 0, triggerobject_etas[idx], triggerobject_phis[idx]); // We check the deltaR match as well as that the pt and eta of the @@ -109,22 +109,24 @@ bool matchParticle(const ROOT::Math::PtEtaPhiMVector &particle, bool eta = abs(particle.eta()) < eta_threshold; // if you don't want to do bit matching here, the trigger_bit_value // has to be set to -1 - bool bit = (trigger_bit_value == -1) || - (IntBits(triggerobject_filterbits[idx]).test(trigger_bit_value)); + bool bit = + (trigger_bit_value == -1) || + (IntBits(triggerobject_filterbits[idx]).test(trigger_bit_value)); bool id = triggerobject_ids[idx] == trigger_particle_id_value; Logger::get("trigger::matchParticle") ->debug("-------------------------------------------------------"); Logger::get("trigger::matchParticle") - ->debug("deltaR_threshold: {}, Check: {}", deltaR_threshold, deltaR); + ->debug("deltaR_threshold: {}, Check: {}", deltaR_threshold, + deltaR); Logger::get("trigger::matchParticle") ->debug("deltaR value: {}", - ROOT::Math::VectorUtil::DeltaR(triggerobject, particle)); + ROOT::Math::VectorUtil::DeltaR(triggerobject, particle)); Logger::get("trigger::matchParticle") ->debug("trigger_particle_id_value: {}, Check: {}", - trigger_particle_id_value, id); + trigger_particle_id_value, id); Logger::get("trigger::matchParticle") ->debug("id value: {}", triggerobject_ids[idx]); @@ -137,24 +139,25 @@ bool matchParticle(const ROOT::Math::PtEtaPhiMVector &particle, ->debug("pt_threshold: {}, Check: {}", pt_threshold, pt); Logger::get("trigger::matchParticle") ->debug("pt value (trg): {}, pt value (reco): {}", - triggerobject_pts[idx], particle.pt()); + triggerobject_pts[idx], particle.pt()); Logger::get("trigger::matchParticle") ->debug("eta_threshold: {}, Check: {}", eta_threshold, eta); Logger::get("trigger::matchParticle") ->debug("eta (trg) value: {}, eta (reco) value: {}", - triggerobject_etas[idx], abs(particle.eta())); + triggerobject_etas[idx], abs(particle.eta())); Logger::get("trigger::matchParticle") ->debug("-------------------------------------------------------"); if (deltaR && bit && id && pt && eta) { - // remove the matching object from the object vectors so it cannot be - // matched by the next particle as well (if there is one) + // remove the matching object from the object vectors so it cannot + // be matched by the next particle as well (if there is one) triggerobject_pts.erase(triggerobject_pts.begin() + idx); triggerobject_etas.erase(triggerobject_etas.begin() + idx); triggerobject_phis.erase(triggerobject_phis.begin() + idx); triggerobject_ids.erase(triggerobject_ids.begin() + idx); - triggerobject_filterbits.erase(triggerobject_filterbits.begin() + idx); + triggerobject_filterbits.erase(triggerobject_filterbits.begin() + + idx); return true; } } @@ -207,50 +210,58 @@ ROOT::RDF::RNode SingleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, - const std::string &triggerobject_id, const std::string &triggerobject_filterbit, - const std::string &hlt_path, const float &pt_threshold, const float &eta_threshold, + const std::string &triggerobject_id, + const std::string &triggerobject_filterbit, const std::string &hlt_path, + const float &pt_threshold, const float &eta_threshold, const int &trigger_particle_id_value, const int &trigger_bit_value, const float &deltaR_threshold) { // In nanoAODv12 the type of trigger object ID was changed to UShort_t // For v9 compatibility a type casting is applied - auto [df1, triggerobject_id_column] = utility::Cast, ROOT::RVec>( - df, triggerobject_id+"_v12", "ROOT::VecOps::RVec", triggerobject_id); + auto [df1, triggerobject_id_column] = + utility::Cast, ROOT::RVec>( + df, triggerobject_id + "_v12", "ROOT::VecOps::RVec", + triggerobject_id); // In nanoAODv15 the type of trigger object ID was changed to ULong64_t // For v9 and v12 compatibility a type casting is applied - auto [df2, triggerobject_filterbit_column] = utility::Cast, ROOT::RVec>( - df1, triggerobject_filterbit+"_v15", "ROOT::VecOps::RVec", triggerobject_filterbit); + auto [df2, triggerobject_filterbit_column] = + utility::Cast, ROOT::RVec>( + df1, triggerobject_filterbit + "_v15", + "ROOT::VecOps::RVec", triggerobject_filterbit); - auto trigger_matching = [pt_threshold, eta_threshold, trigger_particle_id_value, - trigger_bit_value, deltaR_threshold]( - bool hlt_path_match, - const ROOT::Math::PtEtaPhiMVector &particle, - ROOT::RVec triggerobject_pts, - ROOT::RVec triggerobject_etas, - ROOT::RVec triggerobject_phis, - ROOT::RVec triggerobject_ids_v12, - ROOT::RVec triggerobject_filterbits_v15) { - auto triggerobject_ids = static_cast>(triggerobject_ids_v12); - auto triggerobject_filterbits = static_cast>(triggerobject_filterbits_v15); + auto trigger_matching = + [pt_threshold, eta_threshold, trigger_particle_id_value, + trigger_bit_value, deltaR_threshold]( + bool hlt_path_match, const ROOT::Math::PtEtaPhiMVector &particle, + ROOT::RVec triggerobject_pts, + ROOT::RVec triggerobject_etas, + ROOT::RVec triggerobject_phis, + ROOT::RVec triggerobject_ids_v12, + ROOT::RVec triggerobject_filterbits_v15) { + auto triggerobject_ids = + static_cast>(triggerobject_ids_v12); + auto triggerobject_filterbits = + static_cast>(triggerobject_filterbits_v15); - bool match_result = false; - if (hlt_path_match) { + bool match_result = false; + if (hlt_path_match) { + Logger::get("trigger::SingleObjectFlag") + ->debug("Checking triggerobject match with particle ...."); + match_result = matchParticle( + particle, triggerobject_pts, triggerobject_etas, + triggerobject_phis, triggerobject_ids, + triggerobject_filterbits, pt_threshold, eta_threshold, + trigger_particle_id_value, trigger_bit_value, + deltaR_threshold); + } + bool result = hlt_path_match & match_result; Logger::get("trigger::SingleObjectFlag") - ->debug("Checking triggerobject match with particle ...."); - match_result = matchParticle( - particle, triggerobject_pts, triggerobject_etas, - triggerobject_phis, triggerobject_ids, triggerobject_filterbits, - pt_threshold, eta_threshold, trigger_particle_id_value, - trigger_bit_value, deltaR_threshold); - } - bool result = hlt_path_match & match_result; - Logger::get("trigger::SingleObjectFlag") - ->debug("---> HLT Matching: {}", hlt_path_match); - Logger::get("trigger::SingleObjectFlag") - ->debug("---> Object Matching: {}", match_result); - Logger::get("trigger::SingleObjectFlag") - ->debug("--->>>> result: {}", result); - return match_result; - }; + ->debug("---> HLT Matching: {}", hlt_path_match); + Logger::get("trigger::SingleObjectFlag") + ->debug("---> Object Matching: {}", match_result); + Logger::get("trigger::SingleObjectFlag") + ->debug("--->>>> result: {}", result); + return match_result; + }; auto available_trigger = df.GetColumnNames(); std::vector matched_trigger_names; std::regex hlt_path_regex = std::regex(hlt_path); @@ -269,20 +280,22 @@ ROOT::RDF::RNode SingleObjectFlag( if (matched_trigger_names.size() == 0) { Logger::get("trigger::SingleObjectFlag") ->debug("No matching trigger for {} found, returning false for " - "trigger flag {}", hlt_path, outputname); + "trigger flag {}", + hlt_path, outputname); auto df3 = df2.Define(outputname, []() { return false; }); return df3; } else if (matched_trigger_names.size() > 1) { Logger::get("trigger::SingleObjectFlag") - ->debug("More than one matching trigger found, not implemented yet"); + ->debug( + "More than one matching trigger found, not implemented yet"); throw std::invalid_argument( "received too many matching trigger paths, not implemented yet"); } else { - auto df3 = - df2.Define(outputname, trigger_matching, - {matched_trigger_names[0], particle, triggerobject_pt, - triggerobject_eta, triggerobject_phi, - triggerobject_id_column, triggerobject_filterbit_column}); + auto df3 = df2.Define(outputname, trigger_matching, + {matched_trigger_names[0], particle, + triggerobject_pt, triggerobject_eta, + triggerobject_phi, triggerobject_id_column, + triggerobject_filterbit_column}); return df3; } } @@ -327,44 +340,52 @@ ROOT::RDF::RNode SingleObjectFlag( ROOT::RDF::RNode df, const std::string &outputname, const std::string &particle, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, - const std::string &triggerobject_id, const std::string &triggerobject_filterbit, - const float &pt_threshold, const float &eta_threshold, - const int &trigger_particle_id_value, const int &trigger_bit_value, - const float &deltaR_threshold) { + const std::string &triggerobject_id, + const std::string &triggerobject_filterbit, const float &pt_threshold, + const float &eta_threshold, const int &trigger_particle_id_value, + const int &trigger_bit_value, const float &deltaR_threshold) { // In nanoAODv12 the type of trigger object ID was changed to UShort_t // For v9 compatibility a type casting is applied - auto [df1, triggerobject_id_column] = utility::Cast, ROOT::RVec>( - df, triggerobject_id+"_v12", "ROOT::VecOps::RVec", triggerobject_id); + auto [df1, triggerobject_id_column] = + utility::Cast, ROOT::RVec>( + df, triggerobject_id + "_v12", "ROOT::VecOps::RVec", + triggerobject_id); // In nanoAODv15 the type of trigger object ID was changed to ULong64_t // For v9 and v12 compatibility a type casting is applied - auto [df2, triggerobject_filterbit_column] = utility::Cast, ROOT::RVec>( - df1, triggerobject_filterbit+"_v15", "ROOT::VecOps::RVec", triggerobject_filterbit); + auto [df2, triggerobject_filterbit_column] = + utility::Cast, ROOT::RVec>( + df1, triggerobject_filterbit + "_v15", + "ROOT::VecOps::RVec", triggerobject_filterbit); - auto trigger_matching = [pt_threshold, eta_threshold, trigger_particle_id_value, - trigger_bit_value, deltaR_threshold]( - const ROOT::Math::PtEtaPhiMVector &particle, - ROOT::RVec triggerobject_pts, - ROOT::RVec triggerobject_etas, - ROOT::RVec triggerobject_phis, - ROOT::RVec triggerobject_ids_v12, - ROOT::RVec triggerobject_filterbits_v15) { - auto triggerobject_ids = static_cast>(triggerobject_ids_v12); - auto triggerobject_filterbits = static_cast>(triggerobject_filterbits_v15); - Logger::get("trigger::SingleObjectFlag") - ->debug("Checking triggerobject match with particle ...."); - bool match_result = matchParticle( - particle, triggerobject_pts, triggerobject_etas, - triggerobject_phis, triggerobject_ids, triggerobject_filterbits, - pt_threshold, eta_threshold, trigger_particle_id_value, - trigger_bit_value, deltaR_threshold); - Logger::get("trigger::SingleObjectFlag") - ->debug("---> Matching: {}", match_result); - return match_result; - }; + auto trigger_matching = + [pt_threshold, eta_threshold, trigger_particle_id_value, + trigger_bit_value, + deltaR_threshold](const ROOT::Math::PtEtaPhiMVector &particle, + ROOT::RVec triggerobject_pts, + ROOT::RVec triggerobject_etas, + ROOT::RVec triggerobject_phis, + ROOT::RVec triggerobject_ids_v12, + ROOT::RVec triggerobject_filterbits_v15) { + auto triggerobject_ids = + static_cast>(triggerobject_ids_v12); + auto triggerobject_filterbits = + static_cast>(triggerobject_filterbits_v15); + Logger::get("trigger::SingleObjectFlag") + ->debug("Checking triggerobject match with particle ...."); + bool match_result = matchParticle( + particle, triggerobject_pts, triggerobject_etas, + triggerobject_phis, triggerobject_ids, triggerobject_filterbits, + pt_threshold, eta_threshold, trigger_particle_id_value, + trigger_bit_value, deltaR_threshold); + Logger::get("trigger::SingleObjectFlag") + ->debug("---> Matching: {}", match_result); + return match_result; + }; auto df3 = df2.Define(outputname, trigger_matching, - {particle, triggerobject_pt, triggerobject_eta, triggerobject_phi, - triggerobject_id_column, triggerobject_filterbit_column}); + {particle, triggerobject_pt, triggerobject_eta, + triggerobject_phi, triggerobject_id_column, + triggerobject_filterbit_column}); return df3; } @@ -431,17 +452,21 @@ ROOT::RDF::RNode DoubleObjectFlag( const std::string &triggerobject_filterbit, const std::string &hlt_path, const float &pt_threshold_1, const float &pt_threshold_2, const float &eta_threshold_1, const float &eta_threshold_2, - const int &trigger_particle_id_value_1, const int &trigger_particle_id_value_2, - const int &trigger_bit_value_1, const int &trigger_bit_value_2, - const float &deltaR_threshold) { + const int &trigger_particle_id_value_1, + const int &trigger_particle_id_value_2, const int &trigger_bit_value_1, + const int &trigger_bit_value_2, const float &deltaR_threshold) { // In nanoAODv12 the type of trigger object ID was changed to UShort_t // For v9 compatibility a type casting is applied - auto [df1, triggerobject_id_column] = utility::Cast, ROOT::RVec>( - df, triggerobject_id+"_v12", "ROOT::VecOps::RVec", triggerobject_id); + auto [df1, triggerobject_id_column] = + utility::Cast, ROOT::RVec>( + df, triggerobject_id + "_v12", "ROOT::VecOps::RVec", + triggerobject_id); // In nanoAODv15 the type of trigger object ID was changed to ULong64_t // For v9 and v12 compatibility a type casting is applied - auto [df2, triggerobject_filterbit_column] = utility::Cast, ROOT::RVec>( - df1, triggerobject_filterbit+"_v15", "ROOT::VecOps::RVec", triggerobject_filterbit); + auto [df2, triggerobject_filterbit_column] = + utility::Cast, ROOT::RVec>( + df1, triggerobject_filterbit + "_v15", + "ROOT::VecOps::RVec", triggerobject_filterbit); auto trigger_matching = [pt_threshold_1, pt_threshold_2, eta_threshold_1, eta_threshold_2, trigger_particle_id_value_1, @@ -454,9 +479,12 @@ ROOT::RDF::RNode DoubleObjectFlag( ROOT::RVec triggerobject_etas, ROOT::RVec triggerobject_phis, ROOT::RVec triggerobject_ids_v12, - ROOT::RVec triggerobject_filterbits_v15) { - auto triggerobject_ids = static_cast>(triggerobject_ids_v12); - auto triggerobject_filterbits = static_cast>(triggerobject_filterbits_v15); + ROOT::RVec + triggerobject_filterbits_v15) { + auto triggerobject_ids = + static_cast>(triggerobject_ids_v12); + auto triggerobject_filterbits = + static_cast>(triggerobject_filterbits_v15); bool match_result_p1 = false; bool match_result_p2 = false; @@ -506,29 +534,31 @@ ROOT::RDF::RNode DoubleObjectFlag( if (matched_trigger_names.size() == 0) { Logger::get("trigger::DoubleObjectFlag") ->debug("No matching trigger for {} found, returning false for " - "trigger flag {}", - hlt_path, outputname); + "trigger flag {}", + hlt_path, outputname); auto df3 = df2.Define(outputname, []() { return false; }); return df3; } else if (matched_trigger_names.size() > 1) { Logger::get("trigger::DoubleObjectFlag") - ->debug("More than one matching trigger found, not implemented yet"); + ->debug( + "More than one matching trigger found, not implemented yet"); throw std::invalid_argument( "received too many matching trigger paths, not implemented yet"); } else { - auto df3 = - df2.Define(outputname, trigger_matching, - {matched_trigger_names[0], particle_1, particle_2, - triggerobject_pt, triggerobject_eta, triggerobject_phi, - triggerobject_id_column, triggerobject_filterbit_column}); + auto df3 = df2.Define(outputname, trigger_matching, + {matched_trigger_names[0], particle_1, particle_2, + triggerobject_pt, triggerobject_eta, + triggerobject_phi, triggerobject_id_column, + triggerobject_filterbit_column}); return df3; } } /** * @brief This function generates a trigger flag based on the trigger object - * matching for the selected objects. This relies on the `trigger::matchParticle` - * function which does the object to trigger object matching test. + * matching for the selected objects. This relies on the + * `trigger::matchParticle` function which does the object to trigger object + * matching test. * * @note This function is defined for double object triggers only. For single * object triggers be referred to the `trigger::SingleObjectFlag` functions. @@ -578,62 +608,68 @@ ROOT::RDF::RNode DoubleObjectFlag( const std::string &particle_1, const std::string &particle_2, const std::string &triggerobject_pt, const std::string &triggerobject_eta, const std::string &triggerobject_phi, const std::string &triggerobject_id, - const std::string &triggerobject_filterbit, - const float &pt_threshold_1, const float &pt_threshold_2, - const float &eta_threshold_1, const float &eta_threshold_2, - const int &trigger_particle_id_value_1, const int &trigger_particle_id_value_2, - const int &trigger_bit_value_1, const int &trigger_bit_value_2, - const float &deltaR_threshold) { + const std::string &triggerobject_filterbit, const float &pt_threshold_1, + const float &pt_threshold_2, const float &eta_threshold_1, + const float &eta_threshold_2, const int &trigger_particle_id_value_1, + const int &trigger_particle_id_value_2, const int &trigger_bit_value_1, + const int &trigger_bit_value_2, const float &deltaR_threshold) { // In nanoAODv12 the type of trigger object ID was changed to UShort_t // For v9 compatibility a type casting is applied - auto [df1, triggerobject_id_column] = utility::Cast, ROOT::RVec>( - df, triggerobject_id+"_v12", "ROOT::VecOps::RVec", triggerobject_id); + auto [df1, triggerobject_id_column] = + utility::Cast, ROOT::RVec>( + df, triggerobject_id + "_v12", "ROOT::VecOps::RVec", + triggerobject_id); // In nanoAODv15 the type of trigger object ID was changed to ULong64_t // For v9 and v12 compatibility a type casting is applied - auto [df2, triggerobject_filterbit_column] = utility::Cast, ROOT::RVec>( - df1, triggerobject_filterbit+"_v15", "ROOT::VecOps::RVec", triggerobject_filterbit); + auto [df2, triggerobject_filterbit_column] = + utility::Cast, ROOT::RVec>( + df1, triggerobject_filterbit + "_v15", + "ROOT::VecOps::RVec", triggerobject_filterbit); - auto trigger_matching = [pt_threshold_1, pt_threshold_2, eta_threshold_1, - eta_threshold_2, trigger_particle_id_value_1, - trigger_particle_id_value_2, trigger_bit_value_1, - trigger_bit_value_2, deltaR_threshold]( - const ROOT::Math::PtEtaPhiMVector &particle_1, - const ROOT::Math::PtEtaPhiMVector &particle_2, - ROOT::RVec triggerobject_pts, - ROOT::RVec triggerobject_etas, - ROOT::RVec triggerobject_phis, - ROOT::RVec triggerobject_ids_v12, - ROOT::RVec triggerobject_filterbits_v15) { - auto triggerobject_ids = static_cast>(triggerobject_ids_v12); - auto triggerobject_filterbits = static_cast>(triggerobject_filterbits_v15); - Logger::get("trigger::DoubleObjectFlag") - ->debug("Checking triggerobject match with particle ...."); - Logger::get("trigger::DoubleObjectFlag")->debug("First particle"); - bool match_result_p1 = matchParticle( - particle_1, triggerobject_pts, triggerobject_etas, - triggerobject_phis, triggerobject_ids, triggerobject_filterbits, - pt_threshold_1, eta_threshold_1, trigger_particle_id_value_1, - trigger_bit_value_1, deltaR_threshold); - Logger::get("trigger::DoubleObjectFlag")->debug("Second particle"); - bool match_result_p2 = matchParticle( - particle_2, triggerobject_pts, triggerobject_etas, - triggerobject_phis, triggerobject_ids, triggerobject_filterbits, - pt_threshold_2, eta_threshold_2, trigger_particle_id_value_2, - trigger_bit_value_2, deltaR_threshold); - bool result = match_result_p1 & match_result_p2; - Logger::get("trigger::DoubleObjectFlag") - ->debug("---> Matching p1: {}", match_result_p1); - Logger::get("trigger::DoubleObjectFlag") - ->debug("---> Matching p2: {}", match_result_p2); - Logger::get("trigger::DoubleObjectFlag") - ->debug("--->>>> result: {}", result); - return result; - }; + auto trigger_matching = + [pt_threshold_1, pt_threshold_2, eta_threshold_1, eta_threshold_2, + trigger_particle_id_value_1, trigger_particle_id_value_2, + trigger_bit_value_1, trigger_bit_value_2, + deltaR_threshold](const ROOT::Math::PtEtaPhiMVector &particle_1, + const ROOT::Math::PtEtaPhiMVector &particle_2, + ROOT::RVec triggerobject_pts, + ROOT::RVec triggerobject_etas, + ROOT::RVec triggerobject_phis, + ROOT::RVec triggerobject_ids_v12, + ROOT::RVec triggerobject_filterbits_v15) { + auto triggerobject_ids = + static_cast>(triggerobject_ids_v12); + auto triggerobject_filterbits = + static_cast>(triggerobject_filterbits_v15); + Logger::get("trigger::DoubleObjectFlag") + ->debug("Checking triggerobject match with particle ...."); + Logger::get("trigger::DoubleObjectFlag")->debug("First particle"); + bool match_result_p1 = matchParticle( + particle_1, triggerobject_pts, triggerobject_etas, + triggerobject_phis, triggerobject_ids, triggerobject_filterbits, + pt_threshold_1, eta_threshold_1, trigger_particle_id_value_1, + trigger_bit_value_1, deltaR_threshold); + Logger::get("trigger::DoubleObjectFlag")->debug("Second particle"); + bool match_result_p2 = matchParticle( + particle_2, triggerobject_pts, triggerobject_etas, + triggerobject_phis, triggerobject_ids, triggerobject_filterbits, + pt_threshold_2, eta_threshold_2, trigger_particle_id_value_2, + trigger_bit_value_2, deltaR_threshold); + bool result = match_result_p1 & match_result_p2; + Logger::get("trigger::DoubleObjectFlag") + ->debug("---> Matching p1: {}", match_result_p1); + Logger::get("trigger::DoubleObjectFlag") + ->debug("---> Matching p2: {}", match_result_p2); + Logger::get("trigger::DoubleObjectFlag") + ->debug("--->>>> result: {}", result); + return result; + }; auto df3 = df2.Define(outputname, trigger_matching, - {particle_1, particle_2, triggerobject_pt, triggerobject_eta, - triggerobject_phi, triggerobject_id_column, triggerobject_filterbit_column}); + {particle_1, particle_2, triggerobject_pt, triggerobject_eta, + triggerobject_phi, triggerobject_id_column, + triggerobject_filterbit_column}); return df3; } @@ -658,12 +694,12 @@ ROOT::RDF::RNode DoubleObjectFlag( * * @return a new dataframe containing the prescale value column */ -ROOT::RDF::RNode GetPrescaleValues( - ROOT::RDF::RNode df, - correctionManager::CorrectionManager &correction_manager, - const std::string &outputname, const std::string &hlt_path, - const std::string &run, const std::string &lumiblock, - const std::string &prescale_file) { +ROOT::RDF::RNode +GetPrescaleValues(ROOT::RDF::RNode df, + correctionManager::CorrectionManager &correction_manager, + const std::string &outputname, const std::string &hlt_path, + const std::string &run, const std::string &lumiblock, + const std::string &prescale_file) { Logger::get("trigger::GetPrescaleValues") ->debug("reading json from {}", prescale_file); diff --git a/src/tripleselection.cxx b/src/tripleselection.cxx index 9f88b3f1..105393f5 100644 --- a/src/tripleselection.cxx +++ b/src/tripleselection.cxx @@ -292,9 +292,9 @@ namespace three_flavor { /// Events contain at least two good leptons and one good tau, if the /// the two leptonmasks have nonzero elements. These masks are /// constructed using the functions from the physicsobject namespace -/// (e.g. physicsobject::CutMin applied for pT). The argument triple gives -/// information wheather the emt or the met channel is considered. Events -/// with two good electrons or two good muons are vetos immediately. For the +/// (e.g. physicsobject::CutMin applied for pT). The argument triple gives +/// information wheather the emt or the met channel is considered. Events +/// with two good electrons or two good muons are vetos immediately. For the /// fake rate estimation, base leptons are also considered. /// /// \returns an `ROOT::RVec` with three values, the first one beeing diff --git a/src/utility/CorrectionManager.cxx b/src/utility/CorrectionManager.cxx index 852d47fb..b6bc2155 100644 --- a/src/utility/CorrectionManager.cxx +++ b/src/utility/CorrectionManager.cxx @@ -25,7 +25,7 @@ CorrectionManager::loadCorrection(const std::string &filePath, if (filePath_it == correction_map.end()) { Logger::get("CorrectionManager") ->debug("CorrectionFile {} not loaded yet, adding {} to the " - "CorrectionManager...", + "CorrectionManager...", filePath, corrName); auto result = correction_map.emplace( filePath, @@ -69,9 +69,10 @@ CorrectionManager::loadCompoundCorrection(const std::string &filePath, auto filePath_it = correctionCompound_map.find(filePath); if (filePath_it == correctionCompound_map.end()) { Logger::get("CorrectionManager") - ->debug("Compound CorrectionFile {} not loaded yet, adding it to the " - "CorrectionManager...", - filePath); + ->debug( + "Compound CorrectionFile {} not loaded yet, adding it to the " + "CorrectionManager...", + filePath); auto result = correctionCompound_map.emplace( filePath, std::unordered_map< @@ -108,6 +109,7 @@ CorrectionManager::loadCompoundCorrection(const std::string &filePath, * stored in the CorrectionManager. * * @param filePath The path to the json file + * * @return const nlohmann::json */ const nlohmann::json *CorrectionManager::loadjson(const std::string &filePath) { diff --git a/src/utility/OnnxSessionManager.cxx b/src/utility/OnnxSessionManager.cxx index 6e49bbc8..51c5ccaa 100644 --- a/src/utility/OnnxSessionManager.cxx +++ b/src/utility/OnnxSessionManager.cxx @@ -119,4 +119,4 @@ void prepare_model(Ort::Session *session, auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo(); output_node_dims = output_tensor_info.GetShape(); } -} // namespace onnxhelper \ No newline at end of file +} // namespace onnxhelper diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1f1e8228..9069e29e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,46 +1,72 @@ # Add target to download input file -add_test(NAME download_sample - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND curl -OL https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/nanoAOD.root) -set_tests_properties(download_sample PROPERTIES FIXTURES_SETUP download_sample LABELS ntuple_download) +add_test( + NAME download_sample + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND curl -OL + https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/nanoAOD.root) +set_tests_properties(download_sample PROPERTIES FIXTURES_SETUP download_sample + LABELS ntuple_download) # Generate a test for each generated target foreach(TARGET_NAME ${TARGET_NAMES}) - message(STATUS "Add test for target ${TARGET_NAME}") - add_test(NAME crown_ntuple_${TARGET_NAME} - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root nanoAOD.root) - set_tests_properties(crown_ntuple_${TARGET_NAME} PROPERTIES FIXTURES_REQUIRED download_sample LABELS ntuple_run) + message(STATUS "Add test for target ${TARGET_NAME}") + add_test( + NAME crown_ntuple_${TARGET_NAME} + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root nanoAOD.root) + set_tests_properties( + crown_ntuple_${TARGET_NAME} PROPERTIES FIXTURES_REQUIRED download_sample + LABELS ntuple_run) endforeach() - -# add friend tree test -# Add target to download input file -add_test(NAME single_friend_download_sample - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND curl -OL https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/CrownNtuple.root) -set_tests_properties(single_friend_download_sample PROPERTIES FIXTURES_SETUP single_friend_download_sample LABELS single_friend_download) +# add friend tree test Add target to download input file +add_test( + NAME single_friend_download_sample + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND + curl -OL + https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/CrownNtuple.root) +set_tests_properties( + single_friend_download_sample + PROPERTIES FIXTURES_SETUP single_friend_download_sample LABELS + single_friend_download) # Generate a test for each generated target foreach(TARGET_NAME ${TARGET_NAMES}) - message(STATUS "Add test for target ${TARGET_NAME}") - add_test(NAME single_friend_ntuple_${TARGET_NAME} - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root CrownNtuple.root) - set_tests_properties(single_friend_ntuple_${TARGET_NAME} PROPERTIES FIXTURES_REQUIRED single_friend_download_sample LABELS single_friend_run) + message(STATUS "Add test for target ${TARGET_NAME}") + add_test( + NAME single_friend_ntuple_${TARGET_NAME} + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root CrownNtuple.root) + set_tests_properties( + single_friend_ntuple_${TARGET_NAME} + PROPERTIES FIXTURES_REQUIRED single_friend_download_sample LABELS + single_friend_run) endforeach() # Add target to download input file -add_test(NAME two_friends_download_sample - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND curl -OL https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/{CrownNtuple_friend.root,CrownNtuple.root} ) -set_tests_properties(two_friends_download_sample PROPERTIES FIXTURES_SETUP two_friends_download_sample LABELS two_friends_download) +add_test( + NAME two_friends_download_sample + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND + curl -OL + https://github.com/KIT-CMS/CROWNTestingSamples/raw/main/{CrownNtuple_friend.root,CrownNtuple.root} +) +set_tests_properties( + two_friends_download_sample + PROPERTIES FIXTURES_SETUP two_friends_download_sample LABELS + two_friends_download) # Generate a test for each generated target foreach(TARGET_NAME ${TARGET_NAMES}) - message(STATUS "Add test for target ${TARGET_NAME}") - add_test(NAME two_friends_ntuple_${TARGET_NAME} - WORKING_DIRECTORY ${INSTALLDIR} - COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root CrownNtuple.root CrownNtuple_friend.root) - set_tests_properties(two_friends_ntuple_${TARGET_NAME} PROPERTIES FIXTURES_REQUIRED two_friends_download_sample LABELS two_friends_run) + message(STATUS "Add test for target ${TARGET_NAME}") + add_test( + NAME two_friends_ntuple_${TARGET_NAME} + WORKING_DIRECTORY ${INSTALLDIR} + COMMAND ${TARGET_NAME} output_${TARGET_NAME}.root CrownNtuple.root + CrownNtuple_friend.root) + set_tests_properties( + two_friends_ntuple_${TARGET_NAME} + PROPERTIES FIXTURES_REQUIRED two_friends_download_sample LABELS + two_friends_run) endforeach()